diff --git a/docs/en/instructions/eventmesh-sdk-java-quickstart.md b/docs/en/instructions/eventmesh-sdk-java-quickstart.md new file mode 100644 index 0000000000..683f0d1cb2 --- /dev/null +++ b/docs/en/instructions/eventmesh-sdk-java-quickstart.md @@ -0,0 +1,120 @@ +## How to run eventmesh-sdk-java demo + +> Eventmesh-sdk-java , as the client, communicated with eventmesh-runtime, used to complete the sending and receiving of message. +> +> Eventmesh-sdk-java supports sync msg, async msg and broadcast msg. Sync msg means the producer sends msg which need the consumer supplies the response msg, Async msg means the producer just sends msg and does not care reply msg.Broadcast msg means the producer send msg once and all the consumer subscribed the broadcast topic will receive the msg. +> +> Eventmesh-sdk-java supports the protocol of HTTP and TCP. + + + +### 1. TCP DEMO + +#### Sync msg + +- create topic + +``` +sh runadmin.sh updateTopic -c ${ClusterName} -t ${topic} -n ${namesrvAddr} +``` + + + +* start consumer ,subscribe topic in previous step. + +``` +Run the main method of cn.webank.eventmesh.client.tcp.demo.SyncResponse +``` + + + +* start producer, send message + +``` +Run the main method of cn.webank.eventmesh.client.tcp.demo.SyncRequest +``` + + + +#### Async msg + +- create topic + +``` +sh runadmin.sh updateTopic -c ${ClusterName} -t ${topic} -n ${namesrvAddr} +``` + + + +- start consumer ,subscribe topic in previous step. + +``` +Run the main method of cn.webank.eventmesh.client.tcp.demo.AsyncSubscribe +``` + + + +start producer, send message + +``` +Run the main method of cn.webank.eventmesh.client.tcp.demo.AsyncPublish +``` + + + +#### Broadcast msg + +- create topic + +``` +sh runadmin.sh updateTopic -c ${ClusterName} -t ${topic} -n ${namesrvAddr} +``` + + + +- start consumer ,subscribe topic in previous step. + +``` +Run the main method of cn.webank.eventmesh.client.tcp.demo.AsyncSubscribeBroadcast +``` + + + +* start producer, send broadcast message + +``` +Run the main method of cn.webank.eventmesh.client.tcp.demo.AsyncPublishBroadcast +``` + +### 2. HTTP DEMO + +> As to http, eventmesh-sdk-java just implements the sending of msg. And it already supports sync msg and async msg. +> +> In the demo ,the field of `content` of the java class `LiteMessage` represents a special protocal, so if you want to use http-client of eventmesh-sdk-java, you just need to design the content of protocal and supply the consumer appliacation at the same time. + + + +#### Sync msg + +> send msg ,producer need waiting until receive the response msg of consumer + +``` +Run the main method of cn.webank.eventmesh.client.http.demo.SyncRequestInstance +``` + + + +> send msg,producer handles the reponse msg in callback + +``` +Run the main method ofcn.webank.eventmesh.client.http.demo.AsyncSyncRequestInstance +``` + + + +#### Async msg + +``` +Run the main method of cn.webank.eventmesh.client.http.demo.AsyncPublishInstance +``` + diff --git a/docs/images/docker/docker-exec.png b/docs/images/docker/docker-exec.png new file mode 100644 index 0000000000..f605921156 Binary files /dev/null and b/docs/images/docker/docker-exec.png differ diff --git a/docs/images/docker/docker-image.png b/docs/images/docker/docker-image.png new file mode 100644 index 0000000000..5ca80021d4 Binary files /dev/null and b/docs/images/docker/docker-image.png differ diff --git a/docs/images/docker/docker-logs.png b/docs/images/docker/docker-logs.png new file mode 100644 index 0000000000..8cd3c4df5b Binary files /dev/null and b/docs/images/docker/docker-logs.png differ diff --git a/docs/images/docker/docker-ps.png b/docs/images/docker/docker-ps.png new file mode 100644 index 0000000000..9ae1c52b2c Binary files /dev/null and b/docs/images/docker/docker-ps.png differ diff --git a/docs/images/eventmesh-test-structure.png b/docs/images/eventmesh-test-structure.png new file mode 100644 index 0000000000..b783f1edb0 Binary files /dev/null and b/docs/images/eventmesh-test-structure.png differ diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/Constants.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/Constants.java new file mode 100644 index 0000000000..6451da47a7 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/Constants.java @@ -0,0 +1,62 @@ +/* + * 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 cn.webank.eventmesh.common; + +public class Constants { + + public static final String DEFAULT_CHARSET = "UTF-8"; + + public static final String TARGET_PROXY_REGION = "TARGET_PROXY_REGION"; + + public static final String CONSTANTS_DEFAULT_REGION_KEY = "default"; + + public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; + + public static final String LANGUAGE_JAVA = "JAVA"; + + public static final String HTTP_PROTOCOL_PREFIX = "http://"; + + public static final int DEFAULT_HTTP_TIME_OUT = 3000; + + public static final String PROXY_MESSAGE_CONST_TTL = "ttl"; + + public static final Integer DEFAULT_CLIENT_UNACK = 12; + + public static final String CONSTANTS_SERVICE_DESC_ENV = "env"; + + public static final String CONSTANTS_SERVICE_DESC_VERSION = "version"; + + public static final String CONSTANTS_INSTANCE_DESC_ENV = "env"; + + public static final String CONSTANTS_INSTANCE_DESC_IDC = "idc"; + + public static final String CONSTANTS_INSTANCE_DESC_DCN = "dcn"; + + public static final String CONSTANTS_INSTANCE_DESC_SYSID = "sysId"; + + public static final String CONSTANTS_INSTANCE_DESC_IP = "ip"; + + public static final String CONSTANTS_INSTANCE_DESC_PORT = "port"; + + public static final String KEY_CONSTANTS_INSTANCE_DESC_PID = "pid"; + + public static final String RMB_UNIQ_ID = "RMB_UNIQ_ID"; + + public static final String IDC_SEPERATER = "-"; + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/IPUtil.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/IPUtil.java new file mode 100644 index 0000000000..5ad6fd3a42 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/IPUtil.java @@ -0,0 +1,150 @@ +/* + * 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 cn.webank.eventmesh.common; + +import io.netty.channel.Channel; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Enumeration; + +public class IPUtil { + + public static String getLocalAddress() { + //获取docker宿主机ip + String dockerHostIp = System.getenv("webank_docker_host_ip"); + if (dockerHostIp != null && !"".equals(dockerHostIp)) + return dockerHostIp; + //priority of networkInterface when generating client ip + String priority = System.getProperty("networkInterface.priority", "eth0 preferList = new ArrayList(); + for (String eth : priority.split("<")) { + preferList.add(eth); + } + NetworkInterface preferNetworkInterface = null; + + try { + Enumeration enumeration1 = NetworkInterface.getNetworkInterfaces(); + while (enumeration1.hasMoreElements()) { + final NetworkInterface networkInterface = enumeration1.nextElement(); +// LOGGER.debug("networkInterface:{}", networkInterface); + + if (!preferList.contains(networkInterface.getName())) { + continue; + } else if (preferNetworkInterface == null) { + preferNetworkInterface = networkInterface; + } + //get the networkInterface that has higher priority + else if (preferList.indexOf(networkInterface.getName()) + > preferList.indexOf(preferNetworkInterface.getName())) { + preferNetworkInterface = networkInterface; + } + } + + // Traversal Network interface to get the first non-loopback and non-private address + ArrayList ipv4Result = new ArrayList(); + ArrayList ipv6Result = new ArrayList(); + + if (preferNetworkInterface != null) { +// LOGGER.info("use preferNetworkInterface:{}", preferNetworkInterface); + final Enumeration en = preferNetworkInterface.getInetAddresses(); + getIpResult(ipv4Result, ipv6Result, en); + } else { +// LOGGER.info("no preferNetworkInterface"); + Enumeration enumeration = NetworkInterface.getNetworkInterfaces(); + while (enumeration.hasMoreElements()) { + final NetworkInterface networkInterface = enumeration.nextElement(); + final Enumeration en = networkInterface.getInetAddresses(); + getIpResult(ipv4Result, ipv6Result, en); + } + } + + // prefer ipv4 + if (!ipv4Result.isEmpty()) { + for (String ip : ipv4Result) { + if (ip.startsWith("127.0") || ip.startsWith("192.168")) { + continue; + } + + return ip; + } + + return ipv4Result.get(ipv4Result.size() - 1); + } else if (!ipv6Result.isEmpty()) { + return ipv6Result.get(0); + } + //If failed to find,fall back to localhost + final InetAddress localHost = InetAddress.getLocalHost(); + return normalizeHostAddress(localHost); + } catch (SocketException e) { + e.printStackTrace(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + + return null; + } + + private static void getIpResult(ArrayList ipv4Result, ArrayList ipv6Result, + Enumeration en) { + while (en.hasMoreElements()) { + final InetAddress address = en.nextElement(); + if (!address.isLoopbackAddress()) { + if (address instanceof Inet6Address) { + ipv6Result.add(normalizeHostAddress(address)); + } else { + ipv4Result.add(normalizeHostAddress(address)); + } + } + } + } + + private static String normalizeHostAddress(final InetAddress localHost) { + if (localHost instanceof Inet6Address) { + return "[" + localHost.getHostAddress() + "]"; + } else { + return localHost.getHostAddress(); + } + } + + + public static String parseChannelRemoteAddr(final Channel channel) { + if (null == channel) { + return ""; + } + SocketAddress remote = channel.remoteAddress(); + final String addr = remote != null ? remote.toString() : ""; + + if (addr.length() > 0) { + int index = addr.lastIndexOf("/"); + if (index >= 0) { + return addr.substring(index + 1); + } + + return addr; + } + + return ""; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/LiteMessage.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/LiteMessage.java new file mode 100644 index 0000000000..7fe682660a --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/LiteMessage.java @@ -0,0 +1,131 @@ +/* + * 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 cn.webank.eventmesh.common; + +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.HashMap; +import java.util.Map; + +public class LiteMessage { + + private String bizSeqNo; + + private String uniqueId; + + private String topic; + + private String content; + + private Map prop; + + private long createTime = System.currentTimeMillis(); + + public LiteMessage() { + } + + public LiteMessage(String bizSeqno, String uniqueId, String topic, + String content) { + this.bizSeqNo = bizSeqno; + this.uniqueId = uniqueId; + this.topic = topic; + this.content = content; + } + + public Map getProp() { + return prop; + } + + public LiteMessage setProp(Map prop) { + this.prop = prop; + return this; + } + + public LiteMessage addProp(String key, String val) { + if (prop == null) { + prop = new HashMap(); + } + prop.put(key, val); + return this; + } + + public String getPropKey(String key) { + if (prop == null) { + return null; + } + return prop.get(key); + } + + public LiteMessage removeProp(String key) { + if (prop == null) { + return this; + } + prop.remove(key); + return this; + } + + public String getBizSeqNo() { + return bizSeqNo; + } + + public LiteMessage setBizSeqNo(String bizSeqNo) { + this.bizSeqNo = bizSeqNo; + return this; + } + + public String getUniqueId() { + return uniqueId; + } + + public LiteMessage setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + return this; + } + + public String getTopic() { + return topic; + } + + public LiteMessage setTopic(String topic) { + this.topic = topic; + return this; + } + + public String getContent() { + return content; + } + + public LiteMessage setContent(String content) { + this.content = content; + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("liteMessage={") + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("uniqueId=").append(uniqueId).append(",") + .append("topic=").append(topic).append(",") + .append("content=").append(content).append(",") + .append("prop=").append(prop).append(",") + .append("createTime=").append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT)) + .append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/ProxyException.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/ProxyException.java new file mode 100644 index 0000000000..d8d32e25de --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/ProxyException.java @@ -0,0 +1,46 @@ +/* + * 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 cn.webank.eventmesh.common; + +public class ProxyException extends Exception { + + public ProxyException() { + } + + public ProxyException(String message) { + super(message); + } + + public ProxyException(String message, Throwable cause) { + super(message, cause); + } + + public ProxyException(Throwable cause) { + super(cause); + } + + public ProxyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public ProxyException(Integer errCode, String errMsg) { + super((new StringBuilder()).append(errCode) + .append("|") + .append(errMsg).toString()); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/ThreadPoolFactory.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/ThreadPoolFactory.java new file mode 100644 index 0000000000..6a92cebaed --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/ThreadPoolFactory.java @@ -0,0 +1,96 @@ +/* + * 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 cn.webank.eventmesh.common; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class ThreadPoolFactory { + + public static ThreadPoolExecutor createThreadPoolExecutor(int core, int max, final String threadName) { + return createThreadPoolExecutor(core, max, threadName, true); + } + + public static ThreadPoolExecutor createThreadPoolExecutor(int core, int max, final String threadName, final boolean isDaemon) { + return createThreadPoolExecutor(core, max, new LinkedBlockingQueue(1000), threadName, isDaemon); + } + + public static ThreadPoolExecutor createThreadPoolExecutor(int core, int max, BlockingQueue blockingQueue, final String threadName, final boolean isDaemon) { + return new ThreadPoolExecutor(core, max, + 10 * 1000, TimeUnit.MILLISECONDS, blockingQueue, new ThreadFactory() { + + private AtomicInteger seq = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + seq.incrementAndGet(); + Thread t = new Thread(r, threadName + seq.get()); + t.setDaemon(isDaemon); + return t; + } + }); + } + + public static ThreadPoolExecutor createThreadPoolExecutor(int core, int max, ThreadFactory threadFactory) { + return createThreadPoolExecutor(core, max, new LinkedBlockingQueue(1000), threadFactory); + } + + public static ThreadPoolExecutor createThreadPoolExecutor(int core, int max, BlockingQueue blockingQueue, ThreadFactory threadFactory) { + return new ThreadPoolExecutor(core, max,10 * 1000, TimeUnit.MILLISECONDS, blockingQueue, threadFactory); + } + + public static ScheduledExecutorService createSingleScheduledExecutor(final String threadName) { + return Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + private AtomicInteger ai = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r, threadName + ai.incrementAndGet()); + thread.setDaemon(true); + return thread; + } + }); + } + + public static ScheduledExecutorService createScheduledExecutor(int core, final String threadName) { + return createScheduledExecutor(core, threadName, true); + } + + public static ScheduledExecutorService createScheduledExecutor(int core, final String threadName, final boolean isDaemon) { + return Executors.newScheduledThreadPool(core, new ThreadFactory() { + private AtomicInteger ai = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r, threadName + ai.incrementAndGet()); + thread.setDaemon(isDaemon); + return thread; + } + }); + } + + public static ScheduledExecutorService createScheduledExecutor(int core, ThreadFactory threadFactory) { + return Executors.newScheduledThreadPool(core, threadFactory); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/ThreadUtil.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/ThreadUtil.java new file mode 100644 index 0000000000..a240c2f0b2 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/ThreadUtil.java @@ -0,0 +1,47 @@ +/* + * 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 cn.webank.eventmesh.common; + +import java.util.concurrent.ThreadLocalRandom; + +public class ThreadUtil { + + public static void randomSleep(int min, int max) throws Exception { + // nextInt is normally exclusive of the top value, so add 1 to make it inclusive + int random = ThreadLocalRandom.current().nextInt(min, max + 1); + Thread.sleep(random); + + } + + public static void randomSleep(int max) throws Exception { + randomSleep(1, max); + } + + public static long getPID() { + String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); + if (processName != null && processName.length() > 0) { + try { + return Long.parseLong(processName.split("@")[0]); + } catch (Exception e) { + return 0; + } + } + + return 0; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/command/HttpCommand.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/command/HttpCommand.java new file mode 100644 index 0000000000..47ab69b621 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/command/HttpCommand.java @@ -0,0 +1,256 @@ +/* + * 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 cn.webank.eventmesh.common.command; + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.body.BaseResponseBody; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import cn.webank.eventmesh.common.protocol.http.header.BaseResponseHeader; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import com.alibaba.fastjson.JSON; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +public class HttpCommand { + + private static AtomicLong requestId = new AtomicLong(0); + + private long opaque; + + private String requestCode; + + public String httpMethod; + + public String httpVersion; + + public Header header; + + public Body body; + + //Command 请求时间 + public long reqTime; + + //Command 回复时间 + public long resTime; + + public CmdType cmdType = CmdType.REQ; + + public HttpCommand() { + this.reqTime = System.currentTimeMillis(); + this.opaque = requestId.incrementAndGet(); + } + + public HttpCommand(String httpMethod, String httpVersion, String requestCode) { + this.httpMethod = httpMethod; + this.httpVersion = httpVersion; + this.reqTime = System.currentTimeMillis(); + this.requestCode = requestCode; + this.opaque = requestId.incrementAndGet(); + } + + public HttpCommand createHttpCommandResponse(Header header, + Body body) { + if(StringUtils.isBlank(requestCode)) { + return null; + } + HttpCommand response = new HttpCommand(this.httpMethod, this.httpVersion, this.requestCode); + response.setOpaque(this.opaque); + response.setReqTime(this.reqTime); + response.setHeader(header); + response.setBody(body); + response.setCmdType(CmdType.RES); + response.setResTime(System.currentTimeMillis()); + return response; + } + + public HttpCommand createHttpCommandResponse(Integer retCode, String retMsg) { + if(StringUtils.isBlank(requestCode)) { + return null; + } + HttpCommand response = new HttpCommand(this.httpMethod, this.httpVersion, this.requestCode); + response.setOpaque(this.opaque); + response.setReqTime(this.reqTime); + BaseResponseHeader baseResponseHeader = new BaseResponseHeader(); + baseResponseHeader.setCode(requestCode); + response.setHeader(baseResponseHeader); + BaseResponseBody baseResponseBody = new BaseResponseBody(); + baseResponseBody.setRetCode(retCode); + baseResponseBody.setRetMsg(retMsg); + response.setBody(baseResponseBody); + response.setCmdType(CmdType.RES); + response.setResTime(System.currentTimeMillis()); + return response; + } + + public long getReqTime() { + return reqTime; + } + + public void setReqTime(long reqTime) { + this.reqTime = reqTime; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public long getOpaque() { + return opaque; + } + + public void setOpaque(long opaque) { + this.opaque = opaque; + } + + public CmdType getCmdType() { + return cmdType; + } + + public void setCmdType(CmdType cmdType) { + this.cmdType = cmdType; + } + + public String getHttpMethod() { + return httpMethod; + } + + public void setHttpMethod(String httpMethod) { + this.httpMethod = httpMethod; + } + + public String getHttpVersion() { + return httpVersion; + } + + public void setHttpVersion(String httpVersion) { + this.httpVersion = httpVersion; + } + + public String getRequestCode() { + return requestCode; + } + + public void setRequestCode(String requestCode) { + this.requestCode = requestCode; + } + + public Header getHeader() { + return header; + } + + public void setHeader(Header header) { + this.header = header; + } + + public Body getBody() { + return body; + } + + public void setBody(Body body) { + this.body = body; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("httpCommand={") + .append(cmdType).append(",") + .append(httpMethod).append("/").append(httpVersion).append(",") + .append("requestCode=").append(requestCode).append(",") + .append("opaque=").append(opaque).append(","); + + if (cmdType == CmdType.RES) { + sb.append("cost=").append(resTime - reqTime).append(","); + } + + sb.append("header=").append(header).append(",") + .append("body=").append(body) + .append("}"); + + return sb.toString(); + } + + public String abstractDesc() { + StringBuilder sb = new StringBuilder(); + sb.append("httpCommand={") + .append(cmdType).append(",") + .append(httpMethod).append("/").append(httpVersion).append(",") + .append("requestCode=").append(requestCode).append(",") + .append("opaque=").append(opaque).append(","); + + if (cmdType == CmdType.RES) { + sb.append("cost=").append(resTime - reqTime).append(","); + } + + sb.append("header=").append(header).append(",") + .append("bodySize=").append(body.toString().length()).append("}"); + + return sb.toString(); + } + + public String simpleDesc() { + StringBuilder sb = new StringBuilder(); + sb.append("httpCommand={") + .append(cmdType).append(",") + .append(httpMethod).append("/").append(httpVersion).append(",") + .append("requestCode=").append(requestCode).append("}"); + + return sb.toString(); + } + + public DefaultFullHttpResponse httpResponse() throws Exception { + if (cmdType == CmdType.REQ) { + return null; + } + + DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, + HttpResponseStatus.OK, + Unpooled.wrappedBuffer(JSON.toJSONString(this.getBody()).getBytes(Constants.DEFAULT_CHARSET))); + response.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN + + "; charset=" + Constants.DEFAULT_CHARSET); + response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); + response.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + Map customHeader = this.getHeader().toMap(); + if (MapUtils.isNotEmpty(customHeader)) { + HttpHeaders heads = response.headers(); + for (String key : customHeader.keySet()) { + heads.add(key, (customHeader.get(key) == null) ? "" : customHeader.get(key)); + } + } + return response; + } + + public enum CmdType { + REQ, + RES + } +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/BaseRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/BaseRequestBody.java new file mode 100644 index 0000000000..e321f37273 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/BaseRequestBody.java @@ -0,0 +1,35 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body; + +import java.util.HashMap; +import java.util.Map; + +public class BaseRequestBody extends Body { + + public static BaseRequestBody buildBody(Map bodyParam) { + BaseRequestBody baseRequestBody = new BaseRequestBody(); + return baseRequestBody; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/BaseResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/BaseResponseBody.java new file mode 100644 index 0000000000..a83b3ddd6c --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/BaseResponseBody.java @@ -0,0 +1,66 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body; + + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; + +import java.util.HashMap; +import java.util.Map; + +public class BaseResponseBody extends Body { + + private Integer retCode; + + private String retMsg; + + private long resTime = System.currentTimeMillis(); + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.RETCODE, retCode); + map.put(ProtocolKey.RETMSG, retMsg); + map.put(ProtocolKey.RESTIME, resTime); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/Body.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/Body.java new file mode 100644 index 0000000000..dad0c74ed7 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/Body.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.webank.eventmesh.common.protocol.http.body; + + +import cn.webank.eventmesh.common.protocol.http.body.client.HeartbeatRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.client.UnRegRequestBody; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.eventmesh.common.protocol.http.body.client.RegRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.PushMessageRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.RMBTraceLogRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.ReplyMessageRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageBatchRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageBatchV2RequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; + +import java.util.Map; + +public abstract class Body { + + public abstract Map toMap(); + + public static Body buildBody(String requestCode, Map originalMap) throws Exception { + if (String.valueOf(RequestCode.MSG_BATCH_SEND.getRequestCode()).equals(requestCode)) { + return SendMessageBatchRequestBody.buildBody(originalMap); + } if (String.valueOf(RequestCode.MSG_BATCH_SEND_V2.getRequestCode()).equals(requestCode)) { + return SendMessageBatchV2RequestBody.buildBody(originalMap); + } else if (String.valueOf(RequestCode.MSG_SEND_ASYNC.getRequestCode()).equals(requestCode)) { + return SendMessageRequestBody.buildBody(originalMap); + } else if (String.valueOf(RequestCode.MSG_SEND_SYNC.getRequestCode()).equals(requestCode)) { + return SendMessageRequestBody.buildBody(originalMap); + } else if (String.valueOf(RequestCode.HTTP_PUSH_CLIENT_ASYNC.getRequestCode()).equals(requestCode)) { + return PushMessageRequestBody.buildBody(originalMap); + } else if (String.valueOf(RequestCode.HTTP_PUSH_CLIENT_SYNC.getRequestCode()).equals(requestCode)) { + return PushMessageRequestBody.buildBody(originalMap); + } else if (String.valueOf(RequestCode.REGISTER.getRequestCode()).equals(requestCode)) { + return RegRequestBody.buildBody(originalMap); + } else if (String.valueOf(RequestCode.UNREGISTER.getRequestCode()).equals(requestCode)) { + return UnRegRequestBody.buildBody(originalMap); + } else if (String.valueOf(RequestCode.HEARTBEAT.getRequestCode()).equals(requestCode)) { + return HeartbeatRequestBody.buildBody(originalMap); + } else if (String.valueOf(RequestCode.REPLY_MESSAGE.getRequestCode()).equals(requestCode)) { + return ReplyMessageRequestBody.buildBody(originalMap); + } else if (String.valueOf(RequestCode.ADMIN_SHUTDOWN.getRequestCode()).equals(requestCode)) { + return BaseRequestBody.buildBody(originalMap); + } else if (String.valueOf(RequestCode.MSG_TRACE_LOG.getRequestCode()).equals(requestCode)) { + return RMBTraceLogRequestBody.buildBody(originalMap); + } else { + throw new Exception(); + } + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/HeartbeatRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/HeartbeatRequestBody.java new file mode 100644 index 0000000000..fa87498852 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/HeartbeatRequestBody.java @@ -0,0 +1,93 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.client; + +import cn.webank.eventmesh.common.protocol.http.body.Body; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import org.apache.commons.collections4.MapUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class HeartbeatRequestBody extends Body { + + public static final String CLIENTTYPE = "clientType"; + public static final String HEARTBEATENTITIES = "heartbeatEntities"; + + + private String clientType; + + private List heartbeatEntities; + + public String getClientType() { + return clientType; + } + + public void setClientType(String clientType) { + this.clientType = clientType; + } + + public List getHeartbeatEntities() { + return heartbeatEntities; + } + + public void setHeartbeatEntities(List heartbeatEntities) { + this.heartbeatEntities = heartbeatEntities; + } + + public static HeartbeatRequestBody buildBody(Map bodyParam) { + HeartbeatRequestBody body = new HeartbeatRequestBody(); + body.setClientType(MapUtils.getString(bodyParam, CLIENTTYPE)); + body.setHeartbeatEntities(JSONArray.parseArray(MapUtils.getString(bodyParam, HEARTBEATENTITIES), HeartbeatEntity.class)); + return body; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(CLIENTTYPE, clientType); + map.put(HEARTBEATENTITIES, JSON.toJSONString(heartbeatEntities)); + return map; + } + + public static class HeartbeatEntity { + public String topic; + public String serviceId; + public String instanceId; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("heartbeatEntity={") + .append("topic=").append(topic).append(",") + .append("heartbeatEntities=").append(serviceId).append(",") + .append("instanceId=").append(instanceId).append("}"); + return sb.toString(); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("heartbeatRequestBody={") + .append("clientType=").append(clientType).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/HeartbeatResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/HeartbeatResponseBody.java new file mode 100644 index 0000000000..0c00ee3925 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/HeartbeatResponseBody.java @@ -0,0 +1,90 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.client; + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.HashMap; +import java.util.Map; + +public class HeartbeatResponseBody extends Body { + + //响应码 + private Integer retCode; + + //响应信息 + private String retMsg; + + //回复时间 + private long resTime = System.currentTimeMillis(); + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public static HeartbeatResponseBody buildBody(Integer retCode, String retMsg) throws Exception { + HeartbeatResponseBody heartbeatResponseBody = new HeartbeatResponseBody(); + heartbeatResponseBody.setRetMsg(retMsg); + heartbeatResponseBody.setResTime(System.currentTimeMillis()); + heartbeatResponseBody.setRetCode(retCode); + return heartbeatResponseBody; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("heartbeatResponseBody={") + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.RETCODE, retCode); + map.put(ProtocolKey.RETMSG, retMsg); + map.put(ProtocolKey.RESTIME, resTime); + return map; + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/RegRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/RegRequestBody.java new file mode 100644 index 0000000000..746890576b --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/RegRequestBody.java @@ -0,0 +1,93 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.client; + +import cn.webank.eventmesh.common.protocol.http.body.Body; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import org.apache.commons.collections4.MapUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class RegRequestBody extends Body { + + public static final String CLIENTTYPE = "clientType"; + + public static final String TOPICS = "topics"; + + public static final String ENDPOINT = "endpoint"; + + private String clientType; + + private String endPoint; + + private List topics; + + public List getTopics() { + return topics; + } + + public void setTopics(List topics) { + this.topics = topics; + } + + public String getClientType() { + return clientType; + } + + public void setClientType(String clientType) { + this.clientType = clientType; + } + + public String getEndPoint() { + return endPoint; + } + + public void setEndPoint(String endPoint) { + this.endPoint = endPoint; + } + + public static RegRequestBody buildBody(Map bodyParam) { + RegRequestBody body = new RegRequestBody(); + body.setClientType(MapUtils.getString(bodyParam, CLIENTTYPE)); + body.setEndPoint(MapUtils.getString(bodyParam, ENDPOINT)); + body.setTopics(JSONArray.parseArray(MapUtils.getString(bodyParam, TOPICS), String.class)); + return body; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(CLIENTTYPE, clientType); + map.put(ENDPOINT, endPoint); + map.put(TOPICS, JSON.toJSONString(topics)); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("regRequestBody={") + .append("clientType=").append(clientType).append(",") + .append("endPoint=").append(endPoint) + .append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/RegResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/RegResponseBody.java new file mode 100644 index 0000000000..ecaa3e9a7f --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/RegResponseBody.java @@ -0,0 +1,84 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.client; + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.HashMap; +import java.util.Map; + +public class RegResponseBody extends Body { + private Integer retCode; + private String retMsg; + private long resTime = System.currentTimeMillis(); + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public static RegResponseBody buildBody(Integer retCode, String retMsg) throws Exception { + RegResponseBody regResponseBody = new RegResponseBody(); + regResponseBody.setRetMsg(retMsg); + regResponseBody.setResTime(System.currentTimeMillis()); + regResponseBody.setRetCode(retCode); + return regResponseBody; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("regResponseBody={") + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.RETCODE, retCode); + map.put(ProtocolKey.RETMSG, retMsg); + map.put(ProtocolKey.RESTIME, resTime); + return map; + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/SubscribeRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/SubscribeRequestBody.java new file mode 100644 index 0000000000..89a3322511 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/SubscribeRequestBody.java @@ -0,0 +1,21 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.client; + +public class SubscribeRequestBody { +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/SubscribeResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/SubscribeResponseBody.java new file mode 100644 index 0000000000..3218491184 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/SubscribeResponseBody.java @@ -0,0 +1,21 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.client; + +public class SubscribeResponseBody { +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnRegRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnRegRequestBody.java new file mode 100644 index 0000000000..4924e9660a --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnRegRequestBody.java @@ -0,0 +1,95 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.client; + +import cn.webank.eventmesh.common.protocol.http.body.Body; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import org.apache.commons.collections4.MapUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class UnRegRequestBody extends Body { + + public static final String CLIENTTYPE = "clientType"; + + public static final String TOPICS = "topics"; + + private String clientType; + + private List topics; + + public List getTopics() { + return topics; + } + + public void setTopics(List topics) { + this.topics = topics; + } + + public String getClientType() { + return clientType; + } + + public void setClientType(String clientType) { + this.clientType = clientType; + } + + public static UnRegRequestBody buildBody(Map bodyParam) { + UnRegRequestBody body = new UnRegRequestBody(); + body.setClientType(MapUtils.getString(bodyParam, CLIENTTYPE)); + body.setTopics(JSONArray.parseArray(MapUtils.getString(bodyParam, TOPICS), UnRegTopicEntity.class)); + return body; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(CLIENTTYPE, clientType); + map.put(TOPICS, JSON.toJSONString(topics)); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("regRequestBody={") + .append("clientType=").append(clientType) + .append("topics=").append(topics) + .append("}"); + return sb.toString(); + } + + public static class UnRegTopicEntity { + public String topic; + public String serviceId; + public String instanceId; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("unRegTopicEntity={") + .append("topic=").append(topic).append(",") + .append("serviceId=").append(serviceId).append(",") + .append("instanceId=").append(instanceId).append("}"); + return sb.toString(); + } + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnRegResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnRegResponseBody.java new file mode 100644 index 0000000000..7ac28d0bca --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnRegResponseBody.java @@ -0,0 +1,84 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.client; + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.HashMap; +import java.util.Map; + +public class UnRegResponseBody extends Body { + private Integer retCode; + private String retMsg; + private long resTime = System.currentTimeMillis(); + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public static RegResponseBody buildBody(Integer retCode, String retMsg) throws Exception { + RegResponseBody regResponseBody = new RegResponseBody(); + regResponseBody.setRetMsg(retMsg); + regResponseBody.setResTime(System.currentTimeMillis()); + regResponseBody.setRetCode(retCode); + return regResponseBody; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("regResponseBody={") + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.RETCODE, retCode); + map.put(ProtocolKey.RETMSG, retMsg); + map.put(ProtocolKey.RESTIME, resTime); + return map; + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnSubscribeRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnSubscribeRequestBody.java new file mode 100644 index 0000000000..3bfcd7d04e --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnSubscribeRequestBody.java @@ -0,0 +1,21 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.client; + +public class UnSubscribeRequestBody { +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnSubscribeResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnSubscribeResponseBody.java new file mode 100644 index 0000000000..40239067f2 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/client/UnSubscribeResponseBody.java @@ -0,0 +1,21 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.client; + +public class UnSubscribeResponseBody { +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/PushMessageRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/PushMessageRequestBody.java new file mode 100644 index 0000000000..9298dcfd34 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/PushMessageRequestBody.java @@ -0,0 +1,137 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.protocol.http.body.Body; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class PushMessageRequestBody extends Body { + + public static final String RANDOMNO = "randomNo"; + public static final String TOPIC = "topic"; + public static final String BIZSEQNO = "bizSeqNo"; + public static final String UNIQUEID = "uniqueId"; + public static final String CONTENT = "content"; + public static final String EXTFIELDS = "extFields"; + + private String randomNo; + + private String topic; + + private String content; + + private String bizSeqNo; + + private String uniqueId; + + private HashMap extFields; + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public String getRandomNo() { + return randomNo; + } + + public void setRandomNo(String randomNo) { + this.randomNo = randomNo; + } + + public String getBizSeqNo() { + return bizSeqNo; + } + + public void setBizSeqNo(String bizSeqNo) { + this.bizSeqNo = bizSeqNo; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public HashMap getExtFields() { + return extFields; + } + + public void setExtFields(HashMap extFields) { + this.extFields = extFields; + } + + public static PushMessageRequestBody buildBody(final Map bodyParam) { + PushMessageRequestBody pushMessageRequestBody = new PushMessageRequestBody(); + pushMessageRequestBody.setContent(MapUtils.getString(bodyParam, CONTENT)); + pushMessageRequestBody.setBizSeqNo(MapUtils.getString(bodyParam, BIZSEQNO)); + pushMessageRequestBody.setTopic(MapUtils.getString(bodyParam, TOPIC)); + pushMessageRequestBody.setUniqueId(MapUtils.getString(bodyParam, UNIQUEID)); + pushMessageRequestBody.setRandomNo(MapUtils.getString(bodyParam, RANDOMNO)); + String extFields = MapUtils.getString(bodyParam, EXTFIELDS); + if (StringUtils.isNotBlank(extFields)) { + pushMessageRequestBody.setExtFields(JSONObject.parseObject(extFields, HashMap.class)); + } + return pushMessageRequestBody; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(RANDOMNO, randomNo); + map.put(TOPIC, topic); + map.put(CONTENT, content); + map.put(BIZSEQNO, bizSeqNo); + map.put(UNIQUEID, uniqueId); + map.put(EXTFIELDS, JSON.toJSONString(extFields)); + + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("pushMessageRequestBody={") + .append("randomNo=").append(randomNo).append(",") + .append("topic=").append(topic).append(",") + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("uniqueId=").append(uniqueId).append(",") + .append("content=").append(content).append(",") + .append("extFields=").append(extFields).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/PushMessageResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/PushMessageResponseBody.java new file mode 100644 index 0000000000..a462c2a02e --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/PushMessageResponseBody.java @@ -0,0 +1,86 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.HashMap; +import java.util.Map; + +public class PushMessageResponseBody extends Body { + + private Integer retCode; + + private String retMsg; + + private long resTime = System.currentTimeMillis(); + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public static PushMessageResponseBody buildBody(Integer retCode, String retMsg) { + PushMessageResponseBody pushMessageResponseBody = new PushMessageResponseBody(); + pushMessageResponseBody.setResTime(System.currentTimeMillis()); + pushMessageResponseBody.setRetCode(retCode); + pushMessageResponseBody.setRetMsg(retMsg); + return pushMessageResponseBody; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageResponseBody={") + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.RETCODE, retCode); + map.put(ProtocolKey.RETMSG, retMsg); + map.put(ProtocolKey.RESTIME, resTime); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/RMBTraceLogRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/RMBTraceLogRequestBody.java new file mode 100644 index 0000000000..cb6b890614 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/RMBTraceLogRequestBody.java @@ -0,0 +1,164 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.protocol.http.body.Body; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class RMBTraceLogRequestBody extends Body { + + /////////////////////////////////RMB-TRACE//////////////////////////// + public static final String LOG_LEVEL = "level"; + public static final String LOG_POINT = "logPoint"; + public static final String LOG_MESSAGE = "message"; + public static final String LOG_MODEL = "model"; + public static final String LOG_RETCODE = "retCode"; + public static final String LOG_RETMSG = "retMsg"; + public static final String LOG_LANG = "lang"; + public static final String LOG_EXTFIELDS = "extFields"; + + private String level; + + private String logPoint; + + private String message; + + private String model; + + private String retCode; + + private String retMsg; + + private String lang; + + private HashMap extFields = new HashMap(); + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + public String getLogPoint() { + return logPoint; + } + + public void setLogPoint(String logPoint) { + this.logPoint = logPoint; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getRetCode() { + return retCode; + } + + public void setRetCode(String retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public String getLang() { + return lang; + } + + public void setLang(String lang) { + this.lang = lang; + } + + public HashMap getExtFields() { + return extFields; + } + + public void setExtFields(HashMap extFields) { + this.extFields = extFields; + } + + public static RMBTraceLogRequestBody buildBody(Map bodyParam) { + RMBTraceLogRequestBody body = new RMBTraceLogRequestBody(); + body.setLang(MapUtils.getString(bodyParam, LOG_LANG)); + body.setLevel(MapUtils.getString(bodyParam, LOG_LEVEL)); + body.setLogPoint(MapUtils.getString(bodyParam, LOG_POINT)); + body.setMessage(MapUtils.getString(bodyParam, LOG_MESSAGE)); + body.setModel(MapUtils.getString(bodyParam, LOG_MODEL)); + body.setRetCode(MapUtils.getString(bodyParam, LOG_RETCODE)); + body.setRetMsg(MapUtils.getString(bodyParam, LOG_RETMSG)); + String extFields = MapUtils.getString(bodyParam, LOG_EXTFIELDS); + if (StringUtils.isNotBlank(extFields)) { + body.setExtFields(JSONObject.parseObject(extFields, HashMap.class)); + } + return body; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(LOG_EXTFIELDS, extFields); + map.put(LOG_LANG, lang); + map.put(LOG_LEVEL, level); + map.put(LOG_MESSAGE, message); + map.put(LOG_RETMSG, retMsg); + map.put(LOG_MODEL, model); + map.put(LOG_POINT, logPoint); + map.put(LOG_RETCODE, retCode); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("RMBTraceLogRequestBody={") + .append("level=").append(level).append(",") + .append("logPoint=").append(logPoint).append(",") + .append("message=").append(message).append(",") + .append("model=").append(model).append(",") + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("lang=").append(lang).append(",") + .append("extFields=").append(extFields).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/RMBTraceLogResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/RMBTraceLogResponseBody.java new file mode 100644 index 0000000000..64c4696114 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/RMBTraceLogResponseBody.java @@ -0,0 +1,86 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.HashMap; +import java.util.Map; + +public class RMBTraceLogResponseBody extends Body { + + private Integer retCode; + + private String retMsg; + + private long resTime = System.currentTimeMillis(); + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public static RMBTraceLogResponseBody buildBody(Integer retCode, String retMsg) { + RMBTraceLogResponseBody rmbTraceLogResponseBody = new RMBTraceLogResponseBody(); + rmbTraceLogResponseBody.setRetMsg(retMsg); + rmbTraceLogResponseBody.setResTime(System.currentTimeMillis()); + rmbTraceLogResponseBody.setRetCode(retCode); + return rmbTraceLogResponseBody; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("rmbTraceLogResponseBody={") + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.RETCODE, retCode); + map.put(ProtocolKey.RETMSG, retMsg); + map.put(ProtocolKey.RESTIME, resTime); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/ReplyMessageRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/ReplyMessageRequestBody.java new file mode 100644 index 0000000000..6662fa8df0 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/ReplyMessageRequestBody.java @@ -0,0 +1,123 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.protocol.http.body.Body; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class ReplyMessageRequestBody extends Body { + + + public static final String ORIGTOPIC = "origTopic"; + public static final String BIZSEQNO = "bizSeqNo"; + public static final String UNIQUEID = "uniqueId"; + public static final String CONTENT = "content"; + public static final String EXTFIELDS = "extFields"; + + private String bizSeqNo; + + private String uniqueId; + + private String content; + + private String origTopic; + + private HashMap extFields; + + public String getOrigTopic() { + return origTopic; + } + + public void setOrigTopic(String origTopic) { + this.origTopic = origTopic; + } + + public String getBizSeqNo() { + return bizSeqNo; + } + + public void setBizSeqNo(String bizSeqNo) { + this.bizSeqNo = bizSeqNo; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public HashMap getExtFields() { + return extFields; + } + + public void setExtFields(HashMap extFields) { + this.extFields = extFields; + } + + public static ReplyMessageRequestBody buildBody(Map bodyParam) { + ReplyMessageRequestBody body = new ReplyMessageRequestBody(); + body.setBizSeqNo(MapUtils.getString(bodyParam, BIZSEQNO)); + body.setUniqueId(MapUtils.getString(bodyParam, UNIQUEID)); + body.setContent(MapUtils.getString(bodyParam, CONTENT)); + body.setOrigTopic(MapUtils.getString(bodyParam, ORIGTOPIC)); + String extFields = MapUtils.getString(bodyParam, EXTFIELDS); + if (StringUtils.isNotBlank(extFields)) { + body.setExtFields(JSONObject.parseObject(extFields, HashMap.class)); + } + return body; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("replyMessageRequestBody={") + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("uniqueId=").append(uniqueId).append(",") + .append("origTopic=").append(origTopic).append(",") + .append("content=").append(content).append(",") + .append("extFields=").append(extFields).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(BIZSEQNO, bizSeqNo); + map.put(ORIGTOPIC, origTopic); + map.put(UNIQUEID, uniqueId); + map.put(CONTENT, content); + map.put(EXTFIELDS, JSON.toJSONString(extFields)); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/ReplyMessageResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/ReplyMessageResponseBody.java new file mode 100644 index 0000000000..3cdd5371f4 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/ReplyMessageResponseBody.java @@ -0,0 +1,90 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.HashMap; +import java.util.Map; + +public class ReplyMessageResponseBody extends Body { + + //响应码 + private Integer retCode; + + //响应信息 + private String retMsg; + + //回复时间 + private long resTime = System.currentTimeMillis(); + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public static ReplyMessageResponseBody buildBody(Integer retCode, String retMsg) { + ReplyMessageResponseBody replyMessageResponseBody = new ReplyMessageResponseBody(); + replyMessageResponseBody.setRetMsg(retMsg); + replyMessageResponseBody.setResTime(System.currentTimeMillis()); + replyMessageResponseBody.setRetCode(retCode); + return replyMessageResponseBody; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("replyMessageResponseBody={") + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.RETCODE, retCode); + map.put(ProtocolKey.RETMSG, retMsg); + map.put(ProtocolKey.RESTIME, resTime); + return map; + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchRequestBody.java new file mode 100644 index 0000000000..aeaba830b8 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchRequestBody.java @@ -0,0 +1,125 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.protocol.http.body.Body; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SendMessageBatchRequestBody extends Body { + + public static final String BATCHID = "batchId"; + public static final String CONTENTS = "contents"; + public static final String SIZE = "size"; + + private String batchId; + + private List contents; + + private String size; + + public SendMessageBatchRequestBody() { + } + + public String getBatchId() { + return batchId; + } + + public void setBatchId(String batchId) { + this.batchId = batchId; + } + + public List getContents() { + return contents; + } + + public void setContents(List contents) { + this.contents = contents; + } + + public String getSize() { + return size; + } + + public void setSize(String size) { + this.size = size; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageBatchRequestBody={") + .append("batchId=").append(batchId).append(",") + .append("size=").append(size).append(",") + .append("contents=").append(JSON.toJSONString(contents)).append("}"); + return sb.toString(); + } + + public static class BatchMessageEntity { + public String bizSeqNo; + public String topic; + public String msg; + public String tag; + public String ttl; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("batchMessageEntity={") + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("topic=").append(topic).append(",") + .append("msg=").append(msg).append(",") + .append("ttl=").append(ttl).append(",") + .append("tag=").append(tag).append("}"); + return sb.toString(); + } + } + + public static SendMessageBatchRequestBody buildBody(final Map bodyParam) { + String batchId = MapUtils.getString(bodyParam, + BATCHID); + String size = StringUtils.isBlank(MapUtils.getString(bodyParam, + SIZE)) ? "1" : MapUtils.getString(bodyParam, + SIZE); + String contents = MapUtils.getString(bodyParam, + CONTENTS, null); + SendMessageBatchRequestBody body = new SendMessageBatchRequestBody(); + body.setBatchId(batchId); + if (StringUtils.isNotBlank(contents)) { + body.setContents(JSONArray.parseArray(contents, BatchMessageEntity.class)); + } + body.setSize(size); + return body; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(BATCHID, batchId); + map.put(SIZE, size); + map.put(CONTENTS, contents); + return map; + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchResponseBody.java new file mode 100644 index 0000000000..309ecdfd9a --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchResponseBody.java @@ -0,0 +1,89 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageBatchResponseBody extends Body { + + //响应码 + private Integer retCode; + + //响应信息 + private String retMsg; + + //回复时间 + private long resTime = System.currentTimeMillis(); + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public static SendMessageBatchResponseBody buildBody(Integer retCode, String retMsg) { + SendMessageBatchResponseBody sendMessageBatchResponseBody = new SendMessageBatchResponseBody(); + sendMessageBatchResponseBody.setRetMsg(retMsg); + sendMessageBatchResponseBody.setRetCode(retCode); + sendMessageBatchResponseBody.setResTime(System.currentTimeMillis()); + return sendMessageBatchResponseBody; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageBatchResponseBody={") + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.RETCODE, retCode); + map.put(ProtocolKey.RETMSG, retMsg); + map.put(ProtocolKey.RESTIME, resTime); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchV2RequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchV2RequestBody.java new file mode 100644 index 0000000000..0c4683b375 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchV2RequestBody.java @@ -0,0 +1,126 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.protocol.http.body.Body; +import org.apache.commons.collections4.MapUtils; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageBatchV2RequestBody extends Body { + + public static final String BIZSEQNO = "bizSeqNo"; + public static final String TOPIC = "topic"; + public static final String MSG = "msg"; + public static final String TAG = "tag"; + public static final String TTL = "ttl"; + + private String bizSeqNo; + + private String topic; + + private String msg; + + private String tag; + + private String ttl; + + public String getBizSeqNo() { + return bizSeqNo; + } + + public void setBizSeqNo(String bizSeqNo) { + this.bizSeqNo = bizSeqNo; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public String getTtl() { + return ttl; + } + + public void setTtl(String ttl) { + this.ttl = ttl; + } + + public static SendMessageBatchV2RequestBody buildBody(final Map bodyParam) { + String bizSeqno = MapUtils.getString(bodyParam, + BIZSEQNO); + String topic = MapUtils.getString(bodyParam, + TOPIC); + String tag = MapUtils.getString(bodyParam, + TAG); + String msg = MapUtils.getString(bodyParam, + MSG); + String ttl = MapUtils.getString(bodyParam, + TTL); + SendMessageBatchV2RequestBody body = new SendMessageBatchV2RequestBody(); + body.setBizSeqNo(bizSeqno); + body.setMsg(msg); + body.setTag(tag); + body.setTtl(ttl); + body.setTopic(topic); + return body; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(BIZSEQNO, bizSeqNo); + map.put(TOPIC, topic); + map.put(MSG, msg); + map.put(TAG, tag); + map.put(TTL, ttl); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("SendMessageBatchV2RequestBody={") + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("topic=").append(topic).append(",") + .append("tag=").append(tag).append(",") + .append("ttl=").append(ttl).append(",") + .append("msg=").append(msg).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchV2ResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchV2ResponseBody.java new file mode 100644 index 0000000000..b94c796b42 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageBatchV2ResponseBody.java @@ -0,0 +1,89 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageBatchV2ResponseBody extends Body { + + //响应码 + private Integer retCode; + + //响应信息 + private String retMsg; + + //回复时间 + private long resTime = System.currentTimeMillis(); + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public static SendMessageBatchV2ResponseBody buildBody(Integer retCode, String retMsg) { + SendMessageBatchV2ResponseBody sendMessageBatchV2ResponseBody = new SendMessageBatchV2ResponseBody(); + sendMessageBatchV2ResponseBody.setRetMsg(retMsg); + sendMessageBatchV2ResponseBody.setRetCode(retCode); + sendMessageBatchV2ResponseBody.setResTime(System.currentTimeMillis()); + return sendMessageBatchV2ResponseBody; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageBatchV2ResponseBody={") + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.RETCODE, retCode); + map.put(ProtocolKey.RETMSG, retMsg); + map.put(ProtocolKey.RESTIME, resTime); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageRequestBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageRequestBody.java new file mode 100644 index 0000000000..f7b258f211 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageRequestBody.java @@ -0,0 +1,151 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.protocol.http.body.Body; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageRequestBody extends Body { + + public static final String TOPIC = "topic"; + public static final String BIZSEQNO = "bizSeqNo"; + public static final String UNIQUEID = "uniqueId"; + public static final String CONTENT = "content"; + public static final String TTL = "ttl"; + public static final String TAG = "tag"; + public static final String EXTFIELDS = "extFields"; + + + private String topic; + + private String bizSeqNo; + + private String uniqueId; + + private String ttl; + + private String content; + + private String tag; + + private HashMap extFields; + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public String getBizSeqNo() { + return bizSeqNo; + } + + public void setBizSeqNo(String bizSeqNo) { + this.bizSeqNo = bizSeqNo; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public HashMap getExtFields() { + return extFields; + } + + public void setExtFields(HashMap extFields) { + this.extFields = extFields; + } + + public String getTtl() { + return ttl; + } + + public void setTtl(String ttl) { + this.ttl = ttl; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public static SendMessageRequestBody buildBody(Map bodyParam) { + SendMessageRequestBody body = new SendMessageRequestBody(); + body.setTopic(MapUtils.getString(bodyParam, TOPIC)); + body.setBizSeqNo(MapUtils.getString(bodyParam, BIZSEQNO)); + body.setUniqueId(MapUtils.getString(bodyParam, UNIQUEID)); + body.setTtl(MapUtils.getString(bodyParam, TTL)); + body.setTag(MapUtils.getString(bodyParam, TAG, "")); + body.setContent(MapUtils.getString(bodyParam, CONTENT)); + String extFields = MapUtils.getString(bodyParam, EXTFIELDS); + if (StringUtils.isNotBlank(extFields)) { + body.setExtFields(JSONObject.parseObject(extFields, HashMap.class)); + } + return body; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(TOPIC, topic); + map.put(BIZSEQNO, bizSeqNo); + map.put(UNIQUEID, uniqueId); + map.put(TTL, ttl); + map.put(TAG, tag); + map.put(CONTENT, content); + map.put(EXTFIELDS, extFields); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageRequestBody={") + .append("topic=").append(topic).append(",") + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("uniqueId=").append(uniqueId).append(",") + .append("content=").append(content).append(",") + .append("ttl=").append(ttl).append(",") + .append("tag=").append(tag).append(",") + .append("extFields=").append(extFields).append("}"); + return sb.toString(); + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageResponseBody.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageResponseBody.java new file mode 100644 index 0000000000..c05b1fa6fe --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/body/message/SendMessageResponseBody.java @@ -0,0 +1,98 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.body.message; + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageResponseBody extends Body { + + private Integer retCode; + + private String retMsg; + + private long resTime = System.currentTimeMillis(); + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public static SendMessageResponseBody buildBody(Integer retCode, String retMsg) { + SendMessageResponseBody sendMessageResponseBody = new SendMessageResponseBody(); + sendMessageResponseBody.setRetMsg(retMsg); + sendMessageResponseBody.setResTime(System.currentTimeMillis()); + sendMessageResponseBody.setRetCode(retCode); + return sendMessageResponseBody; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageResponseBody={") + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.RETCODE, retCode); + map.put(ProtocolKey.RETMSG, retMsg); + map.put(ProtocolKey.RESTIME, resTime); + return map; + } + + public static class ReplyMessage { + public String topic; + public String body; + public Map properties; + + public ReplyMessage(String topic, String body, Map properties) { + this.topic = topic; + this.body = body; + this.properties = properties; + } + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ClientRetCode.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ClientRetCode.java new file mode 100644 index 0000000000..9b343a6d8a --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ClientRetCode.java @@ -0,0 +1,77 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.common; + +public enum ClientRetCode { + + /** + * 这个RETRY的意思是 客户端发现投递的消息它没有监听时, 告诉PROXY 发往下一个, 重试几次以实现灰度 , 预留 + */ + + OK(1, "ok, SDK返回"), + RETRY(2, "retry, SDK返回, 这种情况需要尝试至多 max(default, config)"), + FAIL(3, "fail, SDK返回"), + NOLISTEN(5, "没有监听, SDK返回, 可用于灰度发布实现, 这种情况需要尝试完所有的url"); + + ClientRetCode(Integer retCode, String errMsg) { + this.retCode = retCode; + this.errMsg = errMsg; + } + + public static boolean contains(Integer clientRetCode) { + boolean flag = false; + for (ClientRetCode itr : ClientRetCode.values()) { + if (itr.retCode.intValue() == clientRetCode.intValue()) { + flag = true; + break; + } + } + return flag; + } + + public static ClientRetCode get(Integer clientRetCode) { + ClientRetCode ret = null; + for (ClientRetCode itr : ClientRetCode.values()) { + if (itr.retCode.intValue() == clientRetCode.intValue()) { + ret = itr; + break; + } + } + return ret; + } + + private Integer retCode; + + private String errMsg; + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getErrMsg() { + return errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ClientType.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ClientType.java new file mode 100644 index 0000000000..f5fc613d9d --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ClientType.java @@ -0,0 +1,71 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.common; + +public enum ClientType { + + PUB(1, "发送客户端"), + + SUB(2, "监听客户端"); + + private Integer type; + + private String desc; + + ClientType(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public static ClientType get(Integer type) { + if (PUB.type.intValue() == type.intValue()) { + return PUB; + } else if (SUB.type.intValue() == type.intValue()) { + return SUB; + } else { + return null; + } + } + + public static boolean contains(Integer clientType) { + boolean flag = false; + for(ClientType ct:ClientType.values()) { + if(ct.type == clientType.intValue()) { + flag = true; + break; + } + } + return flag; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ProtocolKey.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ProtocolKey.java new file mode 100644 index 0000000000..d7a86f4917 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ProtocolKey.java @@ -0,0 +1,55 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.common; + +public class ProtocolKey { + + public static final String REQUEST_CODE = "Code"; + public static final String LANGUAGE = "Language"; + public static final String VERSION = "Version"; + + public static class ClientInstanceKey { + ////////////////////////////////////协议层请求方描述/////////// + public static final String ENV = "Env"; + public static final String REGION = "Region"; + public static final String IDC = "Idc"; + public static final String DCN = "Dcn"; + public static final String SYS = "Sys"; + public static final String PID = "Pid"; + public static final String IP = "Ip"; + public static final String USERNAME = "Username"; + public static final String PASSWD = "Passwd"; + } + + + public static class ProxyInstanceKey { + ///////////////////////////////////////////////协议层PROXY描述 + public static final String PROXYCLUSTER = "ProxyCluster"; + public static final String PROXYIP = "ProxyIp"; + public static final String PROXYENV = "ProxyEnv"; + public static final String PROXYREGION = "ProxyRegion"; + public static final String PROXYIDC = "ProxyIdc"; + public static final String PROXYDCN = "ProxyDcn"; + } + + + //CLIENT <-> PROXY 的 返回 + public static final String RETCODE = "retCode"; + public static final String RETMSG = "retMsg"; + public static final String RESTIME = "resTime"; +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ProtocolVersion.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ProtocolVersion.java new file mode 100644 index 0000000000..27170db721 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ProtocolVersion.java @@ -0,0 +1,59 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.common; + +public enum ProtocolVersion { + + V1("1.0"), + V2("2.0"); + + private String version; + + ProtocolVersion(String version) { + this.version = version; + } + + public static ProtocolVersion get(String version) { + if(V1.version.equals(version)) { + return V1; + } else if(V2.version.equals(version)) { + return V2; + } else { + return null; + } + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public static boolean contains(String version) { + boolean flag = false; + for (ProtocolVersion itr : ProtocolVersion.values()) { + if (itr.version.equals(version)) { + flag = true; + break; + } + } + return flag; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ProxyRetCode.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ProxyRetCode.java new file mode 100644 index 0000000000..c3ec18a646 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/ProxyRetCode.java @@ -0,0 +1,64 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.common; + +public enum ProxyRetCode { + + SUCCESS(0, "success"), + OVERLOAD(1, "proxy overload, try later, "), + PROXY_REQUESTCODE_INVALID(2, "requestCode can't be null, or must be number, "), + PROXY_SEND_SYNC_MSG_ERR(3, "proxy send rr msg err, "), + PROXY_WAITING_RR_MSG_ERR(4, "proxy waiting rr msg err, "), + PROXY_PROTOCOL_HEADER_ERR(6, "proxy protocol[header] err, "), + PROXY_PROTOCOL_BODY_ERR(7, "proxy protocol[body] err, "), + PROXY_STOP(8, "proxy will stop or had stopped, "), + PROXY_REJECT_BY_PROCESSOR_ERROR(9, "proxy reject by processor error, "), + PROXY_BATCH_PRODUCER_STOPED_ERR(10, "proxy batch msg producer stopped, "), + PROXY_SEND_BATCHLOG_MSG_ERR(17, "proxy send batchlog msg err, "), + PROXY_BATCH_SPEED_OVER_LIMIT_ERR(11, "proxy batch msg speed over the limit, "), + PROXY_PACKAGE_MSG_ERR(12, "proxy package msg err, "), + PROXY_GROUP_PRODUCER_STOPED_ERR(13, "proxy group producer stopped, "), + PROXY_SEND_ASYNC_MSG_ERR(14, "proxy send async msg err, "), + PROXY_REPLY_MSG_ERR(15, "proxy reply msg err, "), + PROXY_RUNTIME_ERR(16, "proxy runtime err, "); + + private Integer retCode; + + private String errMsg; + + ProxyRetCode(Integer retCode, String errMsg) { + this.retCode = retCode; + this.errMsg = errMsg; + } + + public Integer getRetCode() { + return retCode; + } + + public void setRetCode(Integer retCode) { + this.retCode = retCode; + } + + public String getErrMsg() { + return errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/RequestCode.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/RequestCode.java new file mode 100644 index 0000000000..aab26ea407 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/common/RequestCode.java @@ -0,0 +1,98 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.common; + +public enum RequestCode { + + MSG_BATCH_SEND(102, "批量发送"), + + MSG_BATCH_SEND_V2(107, "批量发送V2"), + + MSG_SEND_SYNC(101, "单条发送同步消息"), + + MSG_SEND_ASYNC(104, "单条发送异步消息"), + + MSG_TRACE_LOG(103, "日志上报"), + + HTTP_PUSH_CLIENT_ASYNC(105, "PUSH CLIENT BY HTTP POST"), + + HTTP_PUSH_CLIENT_SYNC(106, "PUSH CLIENT BY HTTP POST"), + + REGISTER(201, "注册"), + + UNREGISTER(202, "去注册"), + + HEARTBEAT(203, "心跳, 发送方与消费方分别心跳, 类型区分"), + + SUBSCRIBE(206, "订阅"), + + UNSUBSCRIBE(207, "去订阅"), + + REPLY_MESSAGE(301, "发送返回消息"), + + ADMIN_METRICS(603, "管理接口, METRICS信息"), + + ADMIN_SHUTDOWN(601, "管理接口, SHUTDOWN"); + + private Integer requestCode; + + private String desc; + + RequestCode(Integer requestCode, String desc) { + this.requestCode = requestCode; + this.desc = desc; + } + + public static boolean contains(Integer requestCode) { + boolean flag = false; + for (RequestCode itr : RequestCode.values()) { + if (itr.requestCode.intValue() == requestCode.intValue()) { + flag = true; + break; + } + } + return flag; + } + + public static RequestCode get(Integer requestCode) { + RequestCode ret = null; + for (RequestCode itr : RequestCode.values()) { + if (itr.requestCode.intValue() == requestCode.intValue()) { + ret = itr; + break; + } + } + return ret; + } + + public Integer getRequestCode() { + return requestCode; + } + + public void setRequestCode(Integer requestCode) { + this.requestCode = requestCode; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/BaseRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/BaseRequestHeader.java new file mode 100644 index 0000000000..0094e8bb38 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/BaseRequestHeader.java @@ -0,0 +1,57 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header; + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.commons.collections4.MapUtils; + +import java.util.HashMap; +import java.util.Map; + +public class BaseRequestHeader extends Header { + private String code; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public static BaseRequestHeader buildHeader(Map headerParam) { + BaseRequestHeader header = new BaseRequestHeader(); + header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); + return header; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("baseRequestHeader={code=") + .append(code).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/BaseResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/BaseResponseHeader.java new file mode 100644 index 0000000000..5254f183fe --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/BaseResponseHeader.java @@ -0,0 +1,50 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header; + + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; + +import java.util.HashMap; +import java.util.Map; + +public class BaseResponseHeader extends Header { + + private String code; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public static BaseResponseHeader buildHeader(String code) { + BaseResponseHeader baseResponseHeader = new BaseResponseHeader(); + baseResponseHeader.setCode(code); + return baseResponseHeader; + } + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put(ProtocolKey.REQUEST_CODE, code); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/Header.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/Header.java new file mode 100644 index 0000000000..44c4ba725f --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/Header.java @@ -0,0 +1,68 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header; + + +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.eventmesh.common.protocol.http.header.client.HeartbeatRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.client.RegRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.client.UnRegRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.PushMessageRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageBatchV2RequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.RMBTraceLogRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.ReplyMessageRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageBatchRequestHeader; + +import java.util.Map; + +public abstract class Header { + + public abstract Map toMap(); + + public static Header buildHeader(String requestCode, Map originalMap) throws Exception { + if (String.valueOf(RequestCode.MSG_BATCH_SEND.getRequestCode()).equals(requestCode)) { + return SendMessageBatchRequestHeader.buildHeader(originalMap); + } if (String.valueOf(RequestCode.MSG_BATCH_SEND_V2.getRequestCode()).equals(requestCode)) { + return SendMessageBatchV2RequestHeader.buildHeader(originalMap); + } else if (String.valueOf(RequestCode.MSG_SEND_SYNC.getRequestCode()).equals(requestCode)) { + return SendMessageRequestHeader.buildHeader(originalMap); + } else if (String.valueOf(RequestCode.MSG_SEND_ASYNC.getRequestCode()).equals(requestCode)) { + return SendMessageRequestHeader.buildHeader(originalMap); + } else if (String.valueOf(RequestCode.HTTP_PUSH_CLIENT_ASYNC.getRequestCode()).equals(requestCode)) { + return PushMessageRequestHeader.buildHeader(originalMap); + } else if (String.valueOf(RequestCode.HTTP_PUSH_CLIENT_SYNC.getRequestCode()).equals(requestCode)) { + return PushMessageRequestHeader.buildHeader(originalMap); + } else if (String.valueOf(RequestCode.REGISTER.getRequestCode()).equals(requestCode)) { + return RegRequestHeader.buildHeader(originalMap); + } else if (String.valueOf(RequestCode.UNREGISTER.getRequestCode()).equals(requestCode)) { + return UnRegRequestHeader.buildHeader(originalMap); + } else if (String.valueOf(RequestCode.HEARTBEAT.getRequestCode()).equals(requestCode)) { + return HeartbeatRequestHeader.buildHeader(originalMap); + } else if (String.valueOf(RequestCode.REPLY_MESSAGE.getRequestCode()).equals(requestCode)) { + return ReplyMessageRequestHeader.buildHeader(originalMap); + } else if (String.valueOf(RequestCode.ADMIN_SHUTDOWN.getRequestCode()).equals(requestCode)) { + return BaseRequestHeader.buildHeader(originalMap); + } else if(String.valueOf(RequestCode.MSG_TRACE_LOG.getRequestCode()).equals(requestCode)) { + return RMBTraceLogRequestHeader.buildHeader(originalMap); + } else { + throw new Exception(); + } + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeader.java new file mode 100644 index 0000000000..10a65aa4d8 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeader.java @@ -0,0 +1,219 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.client; + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class HeartbeatRequestHeader extends Header { + + //请求码 + private String code; + + //请求方语言描述 + private String language; + + //请求方采用的协议版本, 默认1.0 + private ProtocolVersion version; + + //请求方所在环境编号 + private String env; + + //请求方所在区域编码 + private String region; + + //请求方所在IDC + private String idc; + + //请求方所在DCN + private String dcn; + + //请求方的子系统 + private String sys; + + //请求方的进程号 + private String pid; + + //请求方的IP + private String ip; + + //请求方的USERNAME + private String username = "username"; + + //请求方的PASSWD + private String passwd = "user@123"; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ProtocolVersion getVersion() { + return version; + } + + public void setVersion(ProtocolVersion version) { + this.version = version; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getDcn() { + return dcn; + } + + public void setDcn(String dcn) { + this.dcn = dcn; + } + + public String getSys() { + return sys; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswd() { + return passwd; + } + + public void setPasswd(String passwd) { + this.passwd = passwd; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.LANGUAGE, language); + map.put(ProtocolKey.VERSION, version); + map.put(ProtocolKey.ClientInstanceKey.ENV, env); + map.put(ProtocolKey.ClientInstanceKey.REGION, region); + map.put(ProtocolKey.ClientInstanceKey.IDC, idc); + map.put(ProtocolKey.ClientInstanceKey.DCN, dcn); + map.put(ProtocolKey.ClientInstanceKey.SYS, sys); + map.put(ProtocolKey.ClientInstanceKey.PID, pid); + map.put(ProtocolKey.ClientInstanceKey.IP, ip); + map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); + map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("heartbeatRequestHeader={") + .append("code=").append(code).append(",") + .append("language=").append(language).append(",") + .append("version=").append(version).append(",") + .append("env=").append(env).append(",") + .append("region=").append(region).append(",") + .append("idc=").append(idc).append(",") + .append("dcn=").append(dcn).append(",") + .append("sys=").append(sys).append(",") + .append("pid=").append(pid).append(",") + .append("ip=").append(ip).append(",") + .append("username=").append(username).append(",") + .append("passwd=").append(passwd).append("}"); + return sb.toString(); + } + + public static HeartbeatRequestHeader buildHeader(Map headerParam) { + HeartbeatRequestHeader header = new HeartbeatRequestHeader(); + header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); + header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); + String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) + ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); + header.setLanguage(lan); + header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); + header.setRegion(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.REGION)); + header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); + header.setDcn(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.DCN)); + header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); + header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); + header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); + header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); + header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); + return header; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeader.java new file mode 100644 index 0000000000..162a6512eb --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeader.java @@ -0,0 +1,139 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.client; + + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.header.Header; + +import java.util.HashMap; +import java.util.Map; + +public class HeartbeatResponseHeader extends Header { + + private int code; + + private String proxyCluster; + + private String proxyIp; + + private String proxyEnv; + + private String proxyRegion; + + private String proxyIdc; + + private String proxyDcn; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getProxyCluster() { + return proxyCluster; + } + + public void setProxyCluster(String proxyCluster) { + this.proxyCluster = proxyCluster; + } + + public String getProxyIp() { + return proxyIp; + } + + public void setProxyIp(String proxyIp) { + this.proxyIp = proxyIp; + } + + public String getProxyEnv() { + return proxyEnv; + } + + public void setProxyEnv(String proxyEnv) { + this.proxyEnv = proxyEnv; + } + + public String getProxyRegion() { + return proxyRegion; + } + + public void setProxyRegion(String proxyRegion) { + this.proxyRegion = proxyRegion; + } + + public String getProxyIdc() { + return proxyIdc; + } + + public void setProxyIdc(String proxyIdc) { + this.proxyIdc = proxyIdc; + } + + public String getProxyDcn() { + return proxyDcn; + } + + public void setProxyDcn(String proxyDcn) { + this.proxyDcn = proxyDcn; + } + + public static HeartbeatResponseHeader buildHeader(Integer requestCode, String proxyCluster, + String proxyIp, String proxyEnv, String proxyRegion, + String proxyDcn, String proxyIDC) { + HeartbeatResponseHeader heartbeatResponseHeader = new HeartbeatResponseHeader(); + heartbeatResponseHeader.setCode(requestCode); + heartbeatResponseHeader.setProxyCluster(proxyCluster); + heartbeatResponseHeader.setProxyDcn(proxyDcn); + heartbeatResponseHeader.setProxyIp(proxyIp); + heartbeatResponseHeader.setProxyEnv(proxyEnv); + heartbeatResponseHeader.setProxyRegion(proxyRegion); + heartbeatResponseHeader.setProxyIdc(proxyIDC); + return heartbeatResponseHeader; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("heartbeatResponseHeader={") + .append("code=").append(code).append(",") + .append("proxyEnv=").append(proxyEnv).append(",") + .append("proxyRegion=").append(proxyRegion).append(",") + .append("proxyIdc=").append(proxyIdc).append(",") + .append("proxyDcn=").append(proxyDcn).append(",") + .append("proxyCluster=").append(proxyCluster).append(",") + .append("proxyIp=").append(proxyIp).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.ProxyInstanceKey.PROXYCLUSTER, proxyCluster); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIP, proxyIp); + map.put(ProtocolKey.ProxyInstanceKey.PROXYENV, proxyEnv); + map.put(ProtocolKey.ProxyInstanceKey.PROXYREGION, proxyRegion); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIDC, proxyIdc); + map.put(ProtocolKey.ProxyInstanceKey.PROXYDCN, proxyDcn); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/RegRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/RegRequestHeader.java new file mode 100644 index 0000000000..4b21501099 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/RegRequestHeader.java @@ -0,0 +1,207 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.client; + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class RegRequestHeader extends Header { + + private String code; + + private String language; + + private ProtocolVersion version; + + private String env; + + private String region; + + private String idc; + + private String dcn; + + private String sys; + + private String pid; + + private String ip; + + private String username = "username"; + + private String passwd = "user@123"; + + public static RegRequestHeader buildHeader(Map headerParam) { + RegRequestHeader header = new RegRequestHeader(); + header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); + header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); + String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) + ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); + header.setLanguage(lan); + header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); + header.setRegion(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.REGION)); + header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); + header.setDcn(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.DCN)); + header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); + header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); + header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); + header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); + header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); + return header; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ProtocolVersion getVersion() { + return version; + } + + public void setVersion(ProtocolVersion version) { + this.version = version; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getDcn() { + return dcn; + } + + public void setDcn(String dcn) { + this.dcn = dcn; + } + + public String getSys() { + return sys; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswd() { + return passwd; + } + + public void setPasswd(String passwd) { + this.passwd = passwd; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.LANGUAGE, language); + map.put(ProtocolKey.VERSION, version); + map.put(ProtocolKey.ClientInstanceKey.ENV, env); + map.put(ProtocolKey.ClientInstanceKey.REGION, region); + map.put(ProtocolKey.ClientInstanceKey.IDC, idc); + map.put(ProtocolKey.ClientInstanceKey.DCN, dcn); + map.put(ProtocolKey.ClientInstanceKey.SYS, sys); + map.put(ProtocolKey.ClientInstanceKey.PID, pid); + map.put(ProtocolKey.ClientInstanceKey.IP, ip); + map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); + map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("regRequestHeader={") + .append("code=").append(code).append(",") + .append("language=").append(language).append(",") + .append("version=").append(version).append(",") + .append("env=").append(env).append(",") + .append("region=").append(region).append(",") + .append("idc=").append(idc).append(",") + .append("dcn=").append(dcn).append(",") + .append("sys=").append(sys).append(",") + .append("pid=").append(pid).append(",") + .append("ip=").append(ip).append(",") + .append("username=").append(username).append(",") + .append("passwd=").append(passwd).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/RegResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/RegResponseHeader.java new file mode 100644 index 0000000000..0da3c147f7 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/RegResponseHeader.java @@ -0,0 +1,147 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.client; + + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.header.Header; + +import java.util.HashMap; +import java.util.Map; + +public class RegResponseHeader extends Header { + + //响应码, 与对应Request的code一致 + private int code; + + //处理该次Request请求的proxy的集群名 + private String proxyCluster; + + //处理该次Request请求的proxy的IP + private String proxyIp; + + //处理该次Request请求的proxy所在的环境编号 + private String proxyEnv; + + //处理该次Request请求的proxy所在区域 + private String proxyRegion; + + //处理该次Request请求的proxy所在IDC + private String proxyIdc; + + //处理该次Request请求的proxy所在DCN + private String proxyDcn; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getProxyCluster() { + return proxyCluster; + } + + public void setProxyCluster(String proxyCluster) { + this.proxyCluster = proxyCluster; + } + + public String getProxyIp() { + return proxyIp; + } + + public void setProxyIp(String proxyIp) { + this.proxyIp = proxyIp; + } + + public String getProxyEnv() { + return proxyEnv; + } + + public void setProxyEnv(String proxyEnv) { + this.proxyEnv = proxyEnv; + } + + public String getProxyRegion() { + return proxyRegion; + } + + public void setProxyRegion(String proxyRegion) { + this.proxyRegion = proxyRegion; + } + + public String getProxyIdc() { + return proxyIdc; + } + + public void setProxyIdc(String proxyIdc) { + this.proxyIdc = proxyIdc; + } + + public String getProxyDcn() { + return proxyDcn; + } + + public void setProxyDcn(String proxyDcn) { + this.proxyDcn = proxyDcn; + } + + public static RegResponseHeader buildHeader(Integer requestCode, String proxyCluster, + String proxyIp, String proxyEnv, String proxyRegion, + String proxyDcn, String proxyIDC) { + RegResponseHeader regResponseHeader = new RegResponseHeader(); + regResponseHeader.setCode(requestCode); + regResponseHeader.setProxyCluster(proxyCluster); + regResponseHeader.setProxyDcn(proxyDcn); + regResponseHeader.setProxyIp(proxyIp); + regResponseHeader.setProxyEnv(proxyEnv); + regResponseHeader.setProxyRegion(proxyRegion); + regResponseHeader.setProxyIdc(proxyIDC); + return regResponseHeader; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("regResponseHeader={") + .append("code=").append(code).append(",") + .append("proxyEnv=").append(proxyEnv).append(",") + .append("proxyRegion=").append(proxyRegion).append(",") + .append("proxyIdc=").append(proxyIdc).append(",") + .append("proxyDcn=").append(proxyDcn).append(",") + .append("proxyCluster=").append(proxyCluster).append(",") + .append("proxyIp=").append(proxyIp).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.ProxyInstanceKey.PROXYCLUSTER, proxyCluster); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIP, proxyIp); + map.put(ProtocolKey.ProxyInstanceKey.PROXYENV, proxyEnv); + map.put(ProtocolKey.ProxyInstanceKey.PROXYREGION, proxyRegion); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIDC, proxyIdc); + map.put(ProtocolKey.ProxyInstanceKey.PROXYDCN, proxyDcn); + return map; + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/SubscribeRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/SubscribeRequestHeader.java new file mode 100644 index 0000000000..aa70e5cd11 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/SubscribeRequestHeader.java @@ -0,0 +1,21 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.client; + +public class SubscribeRequestHeader { +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/SubscribeResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/SubscribeResponseHeader.java new file mode 100644 index 0000000000..c9753e69aa --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/SubscribeResponseHeader.java @@ -0,0 +1,21 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.client; + +public class SubscribeResponseHeader { +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnRegRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnRegRequestHeader.java new file mode 100644 index 0000000000..67da669235 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnRegRequestHeader.java @@ -0,0 +1,220 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.client; + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class UnRegRequestHeader extends Header { + + //请求码 + private String code; + + //请求方语言描述 + private String language; + + //请求方采用的协议版本, 默认1.0 + private ProtocolVersion version; + + //请求方所在环境编号 + private String env; + + //请求方所在区域编码 + private String region; + + //请求方所在IDC + private String idc; + + //请求方所在DCN + private String dcn; + + //请求方的子系统 + private String sys; + + //请求方的进程号 + private String pid; + + //请求方的IP + private String ip; + + //请求方的USERNAME + private String username = "username"; + + //请求方的PASSWD + private String passwd = "user@123"; + + public static UnRegRequestHeader buildHeader(Map headerParam) { + UnRegRequestHeader header = new UnRegRequestHeader(); + header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); + header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); + String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) + ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); + header.setLanguage(lan); + header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); + header.setRegion(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.REGION)); + header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); + header.setDcn(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.DCN)); + header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); + header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); + header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); + header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); + header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); + return header; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ProtocolVersion getVersion() { + return version; + } + + public void setVersion(ProtocolVersion version) { + this.version = version; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getDcn() { + return dcn; + } + + public void setDcn(String dcn) { + this.dcn = dcn; + } + + public String getSys() { + return sys; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswd() { + return passwd; + } + + public void setPasswd(String passwd) { + this.passwd = passwd; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.LANGUAGE, language); + map.put(ProtocolKey.VERSION, version); + map.put(ProtocolKey.ClientInstanceKey.ENV, env); + map.put(ProtocolKey.ClientInstanceKey.REGION, region); + map.put(ProtocolKey.ClientInstanceKey.IDC, idc); + map.put(ProtocolKey.ClientInstanceKey.DCN, dcn); + map.put(ProtocolKey.ClientInstanceKey.SYS, sys); + map.put(ProtocolKey.ClientInstanceKey.PID, pid); + map.put(ProtocolKey.ClientInstanceKey.IP, ip); + map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); + map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("unRegRequestHeader={") + .append("code=").append(code).append(",") + .append("language=").append(language).append(",") + .append("version=").append(version).append(",") + .append("env=").append(env).append(",") + .append("region=").append(region).append(",") + .append("idc=").append(idc).append(",") + .append("dcn=").append(dcn).append(",") + .append("sys=").append(sys).append(",") + .append("pid=").append(pid).append(",") + .append("ip=").append(ip).append(",") + .append("username=").append(username).append(",") + .append("passwd=").append(passwd).append("}"); + return sb.toString(); + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnRegResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnRegResponseHeader.java new file mode 100644 index 0000000000..f9cfcc95a1 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnRegResponseHeader.java @@ -0,0 +1,140 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.client; + + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.header.Header; + +import java.util.HashMap; +import java.util.Map; + +public class UnRegResponseHeader extends Header { + + private int code; + + private String proxyCluster; + + private String proxyIp; + + private String proxyEnv; + + private String proxyRegion; + + private String proxyIdc; + + private String proxyDcn; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getProxyCluster() { + return proxyCluster; + } + + public void setProxyCluster(String proxyCluster) { + this.proxyCluster = proxyCluster; + } + + public String getProxyIp() { + return proxyIp; + } + + public void setProxyIp(String proxyIp) { + this.proxyIp = proxyIp; + } + + public String getProxyEnv() { + return proxyEnv; + } + + public void setProxyEnv(String proxyEnv) { + this.proxyEnv = proxyEnv; + } + + public String getProxyRegion() { + return proxyRegion; + } + + public void setProxyRegion(String proxyRegion) { + this.proxyRegion = proxyRegion; + } + + public String getProxyIdc() { + return proxyIdc; + } + + public void setProxyIdc(String proxyIdc) { + this.proxyIdc = proxyIdc; + } + + public String getProxyDcn() { + return proxyDcn; + } + + public void setProxyDcn(String proxyDcn) { + this.proxyDcn = proxyDcn; + } + + public static UnRegResponseHeader buildHeader(Integer requestCode, String proxyCluster, + String proxyIp, String proxyEnv, String proxyRegion, + String proxyDcn, String proxyIDC) { + UnRegResponseHeader regResponseHeader = new UnRegResponseHeader(); + regResponseHeader.setCode(requestCode); + regResponseHeader.setProxyCluster(proxyCluster); + regResponseHeader.setProxyDcn(proxyDcn); + regResponseHeader.setProxyIp(proxyIp); + regResponseHeader.setProxyEnv(proxyEnv); + regResponseHeader.setProxyRegion(proxyRegion); + regResponseHeader.setProxyIdc(proxyIDC); + return regResponseHeader; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("nnRegResponseHeader={") + .append("code=").append(code).append(",") + .append("proxyEnv=").append(proxyEnv).append(",") + .append("proxyRegion=").append(proxyRegion).append(",") + .append("proxyIdc=").append(proxyIdc).append(",") + .append("proxyDcn=").append(proxyDcn).append(",") + .append("proxyCluster=").append(proxyCluster).append(",") + .append("proxyIp=").append(proxyIp).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.ProxyInstanceKey.PROXYCLUSTER, proxyCluster); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIP, proxyIp); + map.put(ProtocolKey.ProxyInstanceKey.PROXYENV, proxyEnv); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIDC, proxyIdc); + map.put(ProtocolKey.ProxyInstanceKey.PROXYREGION, proxyRegion); + map.put(ProtocolKey.ProxyInstanceKey.PROXYDCN, proxyDcn); + return map; + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeader.java new file mode 100644 index 0000000000..3d746ad8d7 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeader.java @@ -0,0 +1,21 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.client; + +public class UnSubscribeRequestHeader { +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeader.java new file mode 100644 index 0000000000..bdfaceeae0 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeader.java @@ -0,0 +1,21 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.client; + +public class UnSubscribeResponseHeader { +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/PushMessageRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/PushMessageRequestHeader.java new file mode 100644 index 0000000000..17800e53e4 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/PushMessageRequestHeader.java @@ -0,0 +1,170 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import org.apache.commons.collections4.MapUtils; + +import java.util.HashMap; +import java.util.Map; + +public class PushMessageRequestHeader extends Header { + + //请求码 + private int code; + + //请求方语言描述 + private String language; + + //请求方采用的协议版本, 默认1.0 + private ProtocolVersion version; + + private String proxyCluster; + + private String proxyIp; + + private String proxyEnv; + + private String proxyRegion; + + private String proxyIdc; + + private String proxyDcn; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getProxyCluster() { + return proxyCluster; + } + + public void setProxyCluster(String proxyCluster) { + this.proxyCluster = proxyCluster; + } + + public String getProxyIp() { + return proxyIp; + } + + public void setProxyIp(String proxyIp) { + this.proxyIp = proxyIp; + } + + public String getProxyEnv() { + return proxyEnv; + } + + public void setProxyEnv(String proxyEnv) { + this.proxyEnv = proxyEnv; + } + + public String getProxyRegion() { + return proxyRegion; + } + + public void setProxyRegion(String proxyRegion) { + this.proxyRegion = proxyRegion; + } + + public String getProxyIdc() { + return proxyIdc; + } + + public void setProxyIdc(String proxyIdc) { + this.proxyIdc = proxyIdc; + } + + public String getProxyDcn() { + return proxyDcn; + } + + public void setProxyDcn(String proxyDcn) { + this.proxyDcn = proxyDcn; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ProtocolVersion getVersion() { + return version; + } + + public void setVersion(ProtocolVersion version) { + this.version = version; + } + + public static PushMessageRequestHeader buildHeader(final Map headerParam) { + PushMessageRequestHeader pushMessageRequestHeader = new PushMessageRequestHeader(); + pushMessageRequestHeader.setCode(MapUtils.getIntValue(headerParam, ProtocolKey.REQUEST_CODE)); + pushMessageRequestHeader.setLanguage(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA)); + pushMessageRequestHeader.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); + pushMessageRequestHeader.setProxyCluster(MapUtils.getString(headerParam, ProtocolKey.ProxyInstanceKey.PROXYCLUSTER)); + pushMessageRequestHeader.setProxyIp(MapUtils.getString(headerParam, ProtocolKey.ProxyInstanceKey.PROXYIP)); + pushMessageRequestHeader.setProxyDcn(MapUtils.getString(headerParam, ProtocolKey.ProxyInstanceKey.PROXYDCN)); + pushMessageRequestHeader.setProxyEnv(MapUtils.getString(headerParam, ProtocolKey.ProxyInstanceKey.PROXYENV)); + pushMessageRequestHeader.setProxyRegion(MapUtils.getString(headerParam, ProtocolKey.ProxyInstanceKey.PROXYREGION)); + pushMessageRequestHeader.setProxyIdc(MapUtils.getString(headerParam, ProtocolKey.ProxyInstanceKey.PROXYIDC)); + return pushMessageRequestHeader; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.LANGUAGE, language); + map.put(ProtocolKey.VERSION, version); + map.put(ProtocolKey.ProxyInstanceKey.PROXYCLUSTER, proxyCluster); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIP, proxyIp); + map.put(ProtocolKey.ProxyInstanceKey.PROXYENV, proxyEnv); + map.put(ProtocolKey.ProxyInstanceKey.PROXYREGION, proxyRegion); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIDC, proxyIdc); + map.put(ProtocolKey.ProxyInstanceKey.PROXYDCN, proxyDcn); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("pushMessageRequestHeader={") + .append("code=").append(code).append(",") + .append("language=").append(language).append(",") + .append("version=").append(version.getVersion()).append(",") + .append("proxyEnv=").append(proxyEnv).append(",") + .append("proxyRegion=").append(proxyRegion).append(",") + .append("proxyIdc=").append(proxyIdc).append(",") + .append("proxyDcn=").append(proxyDcn).append(",") + .append("proxyCluster=").append(proxyCluster).append(",") + .append("proxyIp=").append(proxyIp).append("}"); + return sb.toString(); + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/PushMessageResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/PushMessageResponseHeader.java new file mode 100644 index 0000000000..d31dfd24ab --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/PushMessageResponseHeader.java @@ -0,0 +1,216 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + + + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.header.Header; + +import java.util.HashMap; +import java.util.Map; + +public class PushMessageResponseHeader extends Header { + + //响应码 + private int code; + + //请求方语言描述 + private String language; + + //请求方采用的协议版本, 默认1.0 + private ProtocolVersion version; + + //请求方所在环境编号 + private String env; + + //请求方所在区域编码 + private String region; + + //请求方所在IDC + private String idc; + + //请求方所在DCN + private String dcn; + + //请求方的子系统 + private String sys; + + //请求方的进程号 + private String pid; + + //请求方的IP + private String ip; + + //请求方的USERNAME + private String username = "username"; + + //请求方的PASSWD + private String passwd = "user@123"; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswd() { + return passwd; + } + + public void setPasswd(String passwd) { + this.passwd = passwd; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ProtocolVersion getVersion() { + return version; + } + + public void setVersion(ProtocolVersion version) { + this.version = version; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getDcn() { + return dcn; + } + + public void setDcn(String dcn) { + this.dcn = dcn; + } + + public String getSys() { + return sys; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public static PushMessageResponseHeader buildHeader(int requestCode, String clientEnv, String clientRegion, String clientIDC, + String clientDCN, String clientSysId, String clientPid, String clientIP) { + PushMessageResponseHeader pushMessageResponseHeader = new PushMessageResponseHeader(); + pushMessageResponseHeader.setCode(requestCode); + pushMessageResponseHeader.setVersion(ProtocolVersion.V1); + pushMessageResponseHeader.setLanguage(Constants.LANGUAGE_JAVA); + pushMessageResponseHeader.setEnv(clientEnv); + pushMessageResponseHeader.setRegion(clientRegion); + pushMessageResponseHeader.setIdc(clientIDC); + pushMessageResponseHeader.setDcn(clientDCN); + pushMessageResponseHeader.setSys(clientSysId); + pushMessageResponseHeader.setPid(clientPid); + pushMessageResponseHeader.setIp(clientIP); + return pushMessageResponseHeader; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("pushMessageResponseHeader={") + .append("code=").append(code).append(",") + .append("language=").append(language).append(",") + .append("version=").append(version).append(",") + .append("env=").append(env).append(",") + .append("region=").append(region).append(",") + .append("idc=").append(idc).append(",") + .append("dcn=").append(dcn).append(",") + .append("sys=").append(sys).append(",") + .append("pid=").append(pid).append(",") + .append("ip=").append(ip).append(",") + .append("username=").append(username).append(",") + .append("passwd=").append(passwd).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.LANGUAGE, language); + map.put(ProtocolKey.VERSION, version); + map.put(ProtocolKey.ClientInstanceKey.ENV, env); + map.put(ProtocolKey.ClientInstanceKey.REGION, region); + map.put(ProtocolKey.ClientInstanceKey.IDC, idc); + map.put(ProtocolKey.ClientInstanceKey.DCN, dcn); + map.put(ProtocolKey.ClientInstanceKey.SYS, sys); + map.put(ProtocolKey.ClientInstanceKey.PID, pid); + map.put(ProtocolKey.ClientInstanceKey.IP, ip); + map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); + map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/RMBTraceLogRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/RMBTraceLogRequestHeader.java new file mode 100644 index 0000000000..17431a422e --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/RMBTraceLogRequestHeader.java @@ -0,0 +1,220 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class RMBTraceLogRequestHeader extends Header { + + //请求码 + private String code; + + //请求方语言描述 + private String language; + + //请求方采用的协议版本, 默认1.0 + private ProtocolVersion version; + + //请求方所在环境编号 + private String env; + + //请求方所在区域编码 + private String region; + + //请求方所在IDC + private String idc; + + //请求方所在DCN + private String dcn; + + //请求方的子系统 + private String sys; + + //请求方的进程号 + private String pid; + + //请求方的IP + private String ip; + + //请求方的USERNAME + private String username = "username"; + + //请求方的PASSWD + private String passwd = "user@123"; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ProtocolVersion getVersion() { + return version; + } + + public void setVersion(ProtocolVersion version) { + this.version = version; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getDcn() { + return dcn; + } + + public void setDcn(String dcn) { + this.dcn = dcn; + } + + public String getSys() { + return sys; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswd() { + return passwd; + } + + public void setPasswd(String passwd) { + this.passwd = passwd; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.LANGUAGE, language); + map.put(ProtocolKey.VERSION, version); + map.put(ProtocolKey.ClientInstanceKey.ENV, env); + map.put(ProtocolKey.ClientInstanceKey.REGION, region); + map.put(ProtocolKey.ClientInstanceKey.IDC, idc); + map.put(ProtocolKey.ClientInstanceKey.DCN, dcn); + map.put(ProtocolKey.ClientInstanceKey.SYS, sys); + map.put(ProtocolKey.ClientInstanceKey.PID, pid); + map.put(ProtocolKey.ClientInstanceKey.IP, ip); + map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); + map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); + return map; + } + + public static RMBTraceLogRequestHeader buildHeader(Map headerParam) { + RMBTraceLogRequestHeader header = new RMBTraceLogRequestHeader(); + header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); + header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); + String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) + ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); + header.setLanguage(lan); + header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); + header.setRegion(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.REGION)); + header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); + header.setDcn(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.DCN)); + header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); + header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); + header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); + header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); + header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); + return header; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("RMBTraceLogRequestHeader={") + .append("code=").append(code).append(",") + .append("language=").append(language).append(",") + .append("version=").append(version).append(",") + .append("env=").append(env).append(",") + .append("region=").append(region).append(",") + .append("idc=").append(idc).append(",") + .append("dcn=").append(dcn).append(",") + .append("sys=").append(sys).append(",") + .append("pid=").append(pid).append(",") + .append("ip=").append(ip).append(",") + .append("username=").append(username).append(",") + .append("passwd=").append(passwd).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/RMBTraceLogResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/RMBTraceLogResponseHeader.java new file mode 100644 index 0000000000..2904c792a8 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/RMBTraceLogResponseHeader.java @@ -0,0 +1,147 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.header.Header; + +import java.util.HashMap; +import java.util.Map; + +public class RMBTraceLogResponseHeader extends Header { + + //响应码, 与对应Request的code一致 + private int code; + + //处理该次Request请求的proxy的集群名 + private String proxyCluster; + + //处理该次Request请求的proxy的IP + private String proxyIp; + + //处理该次Request请求的proxy所在的环境编号 + private String proxyEnv; + + //处理该次Request请求的proxy所在区域 + private String proxyRegion; + + //处理该次Request请求的proxy所在IDC + private String proxyIdc; + + //处理该次Request请求的proxy所在DCN + private String proxyDcn; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getProxyCluster() { + return proxyCluster; + } + + public void setProxyCluster(String proxyCluster) { + this.proxyCluster = proxyCluster; + } + + public String getProxyIp() { + return proxyIp; + } + + public void setProxyIp(String proxyIp) { + this.proxyIp = proxyIp; + } + + public String getProxyEnv() { + return proxyEnv; + } + + public void setProxyEnv(String proxyEnv) { + this.proxyEnv = proxyEnv; + } + + public String getProxyRegion() { + return proxyRegion; + } + + public void setProxyRegion(String proxyRegion) { + this.proxyRegion = proxyRegion; + } + + public String getProxyIdc() { + return proxyIdc; + } + + public void setProxyIdc(String proxyIdc) { + this.proxyIdc = proxyIdc; + } + + public String getProxyDcn() { + return proxyDcn; + } + + public void setProxyDcn(String proxyDcn) { + this.proxyDcn = proxyDcn; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.ProxyInstanceKey.PROXYCLUSTER, proxyCluster); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIP, proxyIp); + map.put(ProtocolKey.ProxyInstanceKey.PROXYENV, proxyEnv); + map.put(ProtocolKey.ProxyInstanceKey.PROXYREGION, proxyRegion); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIDC, proxyIdc); + map.put(ProtocolKey.ProxyInstanceKey.PROXYDCN, proxyDcn); + return map; + } + + public static RMBTraceLogResponseHeader buildHeader(Integer requestCode, String proxyCluster, + String proxyIp, String proxyEnv, String proxyRegion, + String proxyDcn, String proxyIDC) { + RMBTraceLogResponseHeader rmbTraceLogResponseHeader = new RMBTraceLogResponseHeader(); + rmbTraceLogResponseHeader.setCode(requestCode); + rmbTraceLogResponseHeader.setProxyCluster(proxyCluster); + rmbTraceLogResponseHeader.setProxyDcn(proxyDcn); + rmbTraceLogResponseHeader.setProxyIp(proxyIp); + rmbTraceLogResponseHeader.setProxyEnv(proxyEnv); + rmbTraceLogResponseHeader.setProxyRegion(proxyRegion); + rmbTraceLogResponseHeader.setProxyIdc(proxyIDC); + return rmbTraceLogResponseHeader; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("rmbTraceLogResponseHeader={") + .append("code=").append(code).append(",") + .append("proxyEnv=").append(proxyEnv).append(",") + .append("proxyRegion=").append(proxyRegion).append(",") + .append("proxyIdc=").append(proxyIdc).append(",") + .append("proxyDcn=").append(proxyDcn).append(",") + .append("proxyCluster=").append(proxyCluster).append(",") + .append("proxyIp=").append(proxyIp).append("}"); + return sb.toString(); + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeader.java new file mode 100644 index 0000000000..b5c132f2fa --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeader.java @@ -0,0 +1,220 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class ReplyMessageRequestHeader extends Header { + + //请求码 + private String code; + + //请求方语言描述 + private String language; + + //请求方采用的协议版本, 默认1.0 + private ProtocolVersion version; + + //请求方所在环境编号 + private String env; + + //请求方所在区域编码 + private String region; + + //请求方所在IDC + private String idc; + + //请求方所在DCN + private String dcn; + + //请求方的子系统 + private String sys; + + //请求方的进程号 + private String pid; + + //请求方的IP + private String ip; + + //请求方的USERNAME + private String username = "username"; + + //请求方的PASSWD + private String passwd = "user@123"; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswd() { + return passwd; + } + + public void setPasswd(String passwd) { + this.passwd = passwd; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ProtocolVersion getVersion() { + return version; + } + + public void setVersion(ProtocolVersion version) { + this.version = version; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getDcn() { + return dcn; + } + + public void setDcn(String dcn) { + this.dcn = dcn; + } + + public String getSys() { + return sys; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public static ReplyMessageRequestHeader buildHeader(Map headerParam) { + ReplyMessageRequestHeader header = new ReplyMessageRequestHeader(); + header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); + header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); + String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) + ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); + header.setLanguage(lan); + header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); + header.setRegion(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.REGION)); + header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); + header.setDcn(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.DCN)); + header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); + header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); + header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); + header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); + header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); + return header; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.LANGUAGE, language); + map.put(ProtocolKey.VERSION, version); + map.put(ProtocolKey.ClientInstanceKey.ENV, env); + map.put(ProtocolKey.ClientInstanceKey.REGION, region); + map.put(ProtocolKey.ClientInstanceKey.IDC, idc); + map.put(ProtocolKey.ClientInstanceKey.DCN, dcn); + map.put(ProtocolKey.ClientInstanceKey.SYS, sys); + map.put(ProtocolKey.ClientInstanceKey.PID, pid); + map.put(ProtocolKey.ClientInstanceKey.IP, ip); + map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); + map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("replyMessageRequestHeader={") + .append("code=").append(code).append(",") + .append("language=").append(language).append(",") + .append("version=").append(version).append(",") + .append("env=").append(env).append(",") + .append("region=").append(region).append(",") + .append("idc=").append(idc).append(",") + .append("dcn=").append(dcn).append(",") + .append("sys=").append(sys).append(",") + .append("pid=").append(pid).append(",") + .append("ip=").append(ip).append(",") + .append("username=").append(username).append(",") + .append("passwd=").append(passwd).append("}"); + return sb.toString(); + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeader.java new file mode 100644 index 0000000000..a1e2feb41a --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeader.java @@ -0,0 +1,146 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.header.Header; + +import java.util.HashMap; +import java.util.Map; + +public class ReplyMessageResponseHeader extends Header { + + //响应码, 与对应Request的code一致 + private int code; + + //处理该次Request请求的proxy的集群名 + private String proxyCluster; + + //处理该次Request请求的proxy的IP + private String proxyIp; + + //处理该次Request请求的proxy所在的环境编号 + private String proxyEnv; + + //处理该次Request请求的proxy所在区域 + private String proxyRegion; + + //处理该次Request请求的proxy所在IDC + private String proxyIdc; + + //处理该次Request请求的proxy所在DCN + private String proxyDcn; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getProxyCluster() { + return proxyCluster; + } + + public void setProxyCluster(String proxyCluster) { + this.proxyCluster = proxyCluster; + } + + public String getProxyIp() { + return proxyIp; + } + + public void setProxyIp(String proxyIp) { + this.proxyIp = proxyIp; + } + + public String getProxyEnv() { + return proxyEnv; + } + + public void setProxyEnv(String proxyEnv) { + this.proxyEnv = proxyEnv; + } + + public String getProxyRegion() { + return proxyRegion; + } + + public void setProxyRegion(String proxyRegion) { + this.proxyRegion = proxyRegion; + } + + public String getProxyIdc() { + return proxyIdc; + } + + public void setProxyIdc(String proxyIdc) { + this.proxyIdc = proxyIdc; + } + + public String getProxyDcn() { + return proxyDcn; + } + + public void setProxyDcn(String proxyDcn) { + this.proxyDcn = proxyDcn; + } + + public static ReplyMessageResponseHeader buildHeader(Integer requestCode, String proxyCluster, + String proxyIp, String proxyEnv, String proxyRegion, + String proxyDcn, String proxyIDC) { + ReplyMessageResponseHeader replyMessageResponseHeader = new ReplyMessageResponseHeader(); + replyMessageResponseHeader.setCode(requestCode); + replyMessageResponseHeader.setProxyCluster(proxyCluster); + replyMessageResponseHeader.setProxyDcn(proxyDcn); + replyMessageResponseHeader.setProxyIp(proxyIp); + replyMessageResponseHeader.setProxyEnv(proxyEnv); + replyMessageResponseHeader.setProxyRegion(proxyRegion); + replyMessageResponseHeader.setProxyIdc(proxyIDC); + return replyMessageResponseHeader; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("replyMessageResponseHeader={") + .append("code=").append(code).append(",") + .append("proxyEnv=").append(proxyEnv).append(",") + .append("proxyRegion=").append(proxyRegion).append(",") + .append("proxyIdc=").append(proxyIdc).append(",") + .append("proxyDcn=").append(proxyDcn).append(",") + .append("proxyCluster=").append(proxyCluster).append(",") + .append("proxyIp=").append(proxyIp).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.ProxyInstanceKey.PROXYCLUSTER, proxyCluster); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIP, proxyIp); + map.put(ProtocolKey.ProxyInstanceKey.PROXYENV, proxyEnv); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIDC, proxyIdc); + map.put(ProtocolKey.ProxyInstanceKey.PROXYREGION, proxyRegion); + map.put(ProtocolKey.ProxyInstanceKey.PROXYDCN, proxyDcn); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchRequestHeader.java new file mode 100644 index 0000000000..622e7bad54 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchRequestHeader.java @@ -0,0 +1,221 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageBatchRequestHeader extends Header { + + //请求码 + private String code; + + //请求方语言描述 + private String language; + + //请求方采用的协议版本, 默认1.0 + private ProtocolVersion version; + + //请求方所在环境编号 + private String env; + + //请求方所在区域编码 + private String region; + + //请求方所在IDC + private String idc; + + //请求方所在DCN + private String dcn; + + //请求方的子系统 + private String sys; + + //请求方的进程号 + private String pid; + + //请求方的IP + private String ip; + + //请求方的USERNAME + private String username = "username"; + + //请求方的PASSWD + private String passwd = "user@123"; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswd() { + return passwd; + } + + public void setPasswd(String passwd) { + this.passwd = passwd; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ProtocolVersion getVersion() { + return version; + } + + public void setVersion(ProtocolVersion version) { + this.version = version; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getDcn() { + return dcn; + } + + public void setDcn(String dcn) { + this.dcn = dcn; + } + + public String getSys() { + return sys; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public static SendMessageBatchRequestHeader buildHeader(final Map headerParam) { + SendMessageBatchRequestHeader header = new SendMessageBatchRequestHeader(); + header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); + header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); + String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) + ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); + header.setLanguage(lan); + header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); + header.setRegion(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.REGION)); + header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); + header.setDcn(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.DCN)); + header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); + header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); + header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); + header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); + header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); + return header; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.LANGUAGE, language); + map.put(ProtocolKey.VERSION, version); + map.put(ProtocolKey.ClientInstanceKey.ENV, env); + map.put(ProtocolKey.ClientInstanceKey.REGION, region); + map.put(ProtocolKey.ClientInstanceKey.IDC, idc); + map.put(ProtocolKey.ClientInstanceKey.DCN, dcn); + map.put(ProtocolKey.ClientInstanceKey.SYS, sys); + map.put(ProtocolKey.ClientInstanceKey.PID, pid); + map.put(ProtocolKey.ClientInstanceKey.IP, ip); + map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); + map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageBatchRequestHeader={") + .append("code=").append(code).append(",") + .append("language=").append(language).append(",") + .append("version=").append(version).append(",") + .append("env=").append(env).append(",") + .append("region=").append(region).append(",") + .append("idc=").append(idc).append(",") + .append("dcn=").append(dcn).append(",") + .append("sys=").append(sys).append(",") + .append("pid=").append(pid).append(",") + .append("ip=").append(ip).append(",") + .append("username=").append(username).append(",") + .append("passwd=").append(passwd).append("}"); + return sb.toString(); + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchResponseHeader.java new file mode 100644 index 0000000000..ea44ea0c9f --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchResponseHeader.java @@ -0,0 +1,146 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.header.Header; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageBatchResponseHeader extends Header { + + //响应码, 与对应Request的code一致 + private int code; + + //处理该次Request请求的proxy的集群名 + private String proxyCluster; + + //处理该次Request请求的proxy的IP + private String proxyIp; + + //处理该次Request请求的proxy所在的环境编号 + private String proxyEnv; + + //处理该次Request请求的proxy所在区域 + private String proxyRegion; + + //处理该次Request请求的proxy所在IDC + private String proxyIdc; + + //处理该次Request请求的proxy所在DCN + private String proxyDcn; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getProxyCluster() { + return proxyCluster; + } + + public void setProxyCluster(String proxyCluster) { + this.proxyCluster = proxyCluster; + } + + public String getProxyIp() { + return proxyIp; + } + + public void setProxyIp(String proxyIp) { + this.proxyIp = proxyIp; + } + + public String getProxyEnv() { + return proxyEnv; + } + + public void setProxyEnv(String proxyEnv) { + this.proxyEnv = proxyEnv; + } + + public String getProxyRegion() { + return proxyRegion; + } + + public void setProxyRegion(String proxyRegion) { + this.proxyRegion = proxyRegion; + } + + public String getProxyIdc() { + return proxyIdc; + } + + public void setProxyIdc(String proxyIdc) { + this.proxyIdc = proxyIdc; + } + + public String getProxyDcn() { + return proxyDcn; + } + + public void setProxyDcn(String proxyDcn) { + this.proxyDcn = proxyDcn; + } + + public static SendMessageBatchResponseHeader buildHeader(Integer requestCode, String proxyCluster, + String proxyIp, String proxyEnv, String proxyRegion, + String proxyDcn, String proxyIDC) { + SendMessageBatchResponseHeader sendMessageBatchResponseHeader = new SendMessageBatchResponseHeader(); + sendMessageBatchResponseHeader.setCode(requestCode); + sendMessageBatchResponseHeader.setProxyCluster(proxyCluster); + sendMessageBatchResponseHeader.setProxyDcn(proxyDcn); + sendMessageBatchResponseHeader.setProxyEnv(proxyEnv); + sendMessageBatchResponseHeader.setProxyRegion(proxyRegion); + sendMessageBatchResponseHeader.setProxyIdc(proxyIDC); + sendMessageBatchResponseHeader.setProxyIp(proxyIp); + return sendMessageBatchResponseHeader; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageBatchResponseHeader={") + .append("code=").append(code).append(",") + .append("proxyEnv=").append(proxyEnv).append(",") + .append("proxyRegion=").append(proxyRegion).append(",") + .append("proxyIdc=").append(proxyIdc).append(",") + .append("proxyDcn=").append(proxyDcn).append(",") + .append("proxyCluster=").append(proxyCluster).append(",") + .append("proxyIp=").append(proxyIp).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.ProxyInstanceKey.PROXYCLUSTER, proxyCluster); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIP, proxyIp); + map.put(ProtocolKey.ProxyInstanceKey.PROXYENV, proxyEnv); + map.put(ProtocolKey.ProxyInstanceKey.PROXYREGION, proxyRegion); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIDC, proxyIdc); + map.put(ProtocolKey.ProxyInstanceKey.PROXYDCN, proxyDcn); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchV2RequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchV2RequestHeader.java new file mode 100644 index 0000000000..daca252db0 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchV2RequestHeader.java @@ -0,0 +1,219 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageBatchV2RequestHeader extends Header { + + //请求码 + private String code; + + //请求方语言描述 + private String language; + + //请求方采用的协议版本, 默认1.0 + private ProtocolVersion version; + + //请求方所在环境编号 + private String env; + + //请求方所在区域编码 + private String region; + + //请求方所在IDC + private String idc; + + //请求方所在DCN + private String dcn; + + //请求方的子系统 + private String sys; + + //请求方的进程号 + private String pid; + + //请求方的IP + private String ip; + + //请求方的USERNAME + private String username = "username"; + + //请求方的PASSWD + private String passwd = "user@123"; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswd() { + return passwd; + } + + public void setPasswd(String passwd) { + this.passwd = passwd; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ProtocolVersion getVersion() { + return version; + } + + public void setVersion(ProtocolVersion version) { + this.version = version; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getDcn() { + return dcn; + } + + public void setDcn(String dcn) { + this.dcn = dcn; + } + + public String getSys() { + return sys; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public static SendMessageBatchV2RequestHeader buildHeader(final Map headerParam) { + SendMessageBatchV2RequestHeader header = new SendMessageBatchV2RequestHeader(); + header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); + header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); + String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) + ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); + header.setLanguage(lan); + header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); + header.setRegion(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.REGION)); + header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); + header.setDcn(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.DCN)); + header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); + header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); + header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); + header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); + header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); + return header; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.LANGUAGE, language); + map.put(ProtocolKey.VERSION, version); + map.put(ProtocolKey.ClientInstanceKey.ENV, env); + map.put(ProtocolKey.ClientInstanceKey.REGION, region); + map.put(ProtocolKey.ClientInstanceKey.IDC, idc); + map.put(ProtocolKey.ClientInstanceKey.DCN, dcn); + map.put(ProtocolKey.ClientInstanceKey.SYS, sys); + map.put(ProtocolKey.ClientInstanceKey.PID, pid); + map.put(ProtocolKey.ClientInstanceKey.IP, ip); + map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); + map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageBatchV2RequestHeader={") + .append("code=").append(code).append(",") + .append("language=").append(language).append(",") + .append("version=").append(version).append(",") + .append("env=").append(env).append(",") + .append("region=").append(region).append(",") + .append("idc=").append(idc).append(",") + .append("dcn=").append(dcn).append(",") + .append("sys=").append(sys).append(",") + .append("pid=").append(pid).append(",") + .append("ip=").append(ip).append(",") + .append("username=").append(username).append(",") + .append("passwd=").append(passwd).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchV2ResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchV2ResponseHeader.java new file mode 100644 index 0000000000..88afd18f87 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageBatchV2ResponseHeader.java @@ -0,0 +1,145 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.header.Header; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageBatchV2ResponseHeader extends Header { + + //响应码, 与对应Request的code一致 + private int code; + + //处理该次Request请求的proxy的集群名 + private String proxyCluster; + + //处理该次Request请求的proxy的IP + private String proxyIp; + + //处理该次Request请求的proxy所在的环境编号 + private String proxyEnv; + + //处理该次Request请求的proxy所在区域 + private String proxyRegion; + + //处理该次Request请求的proxy所在IDC + private String proxyIdc; + + //处理该次Request请求的proxy所在DCN + private String proxyDcn; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getProxyCluster() { + return proxyCluster; + } + + public void setProxyCluster(String proxyCluster) { + this.proxyCluster = proxyCluster; + } + + public String getProxyIp() { + return proxyIp; + } + + public void setProxyIp(String proxyIp) { + this.proxyIp = proxyIp; + } + + public String getProxyEnv() { + return proxyEnv; + } + + public void setProxyEnv(String proxyEnv) { + this.proxyEnv = proxyEnv; + } + + public String getProxyRegion() { + return proxyRegion; + } + + public void setProxyRegion(String proxyRegion) { + this.proxyRegion = proxyRegion; + } + + public String getProxyIdc() { + return proxyIdc; + } + + public void setProxyIdc(String proxyIdc) { + this.proxyIdc = proxyIdc; + } + + public String getProxyDcn() { + return proxyDcn; + } + + public void setProxyDcn(String proxyDcn) { + this.proxyDcn = proxyDcn; + } + + public static SendMessageBatchV2ResponseHeader buildHeader(Integer requestCode, String proxyCluster, + String proxyIp, String proxyEnv, String proxyRegion, + String proxyDcn, String proxyIDC) { + SendMessageBatchV2ResponseHeader header = new SendMessageBatchV2ResponseHeader(); + header.setCode(requestCode); + header.setProxyCluster(proxyCluster); + header.setProxyDcn(proxyDcn); + header.setProxyEnv(proxyEnv); + header.setProxyRegion(proxyRegion); + header.setProxyIdc(proxyIDC); + header.setProxyIp(proxyIp); + return header; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageBatchV2ResponseHeader={") + .append("code=").append(code).append(",") + .append("proxyEnv=").append(proxyEnv).append(",") + .append("proxyRegion=").append(proxyRegion).append(",") + .append("proxyIdc=").append(proxyIdc).append(",") + .append("proxyDcn=").append(proxyDcn).append(",") + .append("proxyCluster=").append(proxyCluster).append(",") + .append("proxyIp=").append(proxyIp).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.ProxyInstanceKey.PROXYCLUSTER, proxyCluster); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIP, proxyIp); + map.put(ProtocolKey.ProxyInstanceKey.PROXYENV, proxyEnv); + map.put(ProtocolKey.ProxyInstanceKey.PROXYREGION, proxyRegion); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIDC, proxyIdc); + map.put(ProtocolKey.ProxyInstanceKey.PROXYDCN, proxyDcn); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageRequestHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageRequestHeader.java new file mode 100644 index 0000000000..52fd0f42e4 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageRequestHeader.java @@ -0,0 +1,220 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageRequestHeader extends Header { + + //请求码 + private String code; + + //请求方语言描述 + private String language; + + //请求方采用的协议版本, 默认1.0 + private ProtocolVersion version; + + //请求方所在环境编号 + private String env; + + //请求方所在区域编码 + private String region; + + //请求方所在IDC + private String idc; + + //请求方所在DCN + private String dcn; + + //请求方的子系统 + private String sys; + + //请求方的进程号 + private String pid; + + //请求方的IP + private String ip; + + //请求方的USERNAME + private String username = "username"; + + //请求方的PASSWD + private String passwd = "user@123"; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswd() { + return passwd; + } + + public void setPasswd(String passwd) { + this.passwd = passwd; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public ProtocolVersion getVersion() { + return version; + } + + public void setVersion(ProtocolVersion version) { + this.version = version; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getDcn() { + return dcn; + } + + public void setDcn(String dcn) { + this.dcn = dcn; + } + + public String getSys() { + return sys; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public static SendMessageRequestHeader buildHeader(Map headerParam) { + SendMessageRequestHeader header = new SendMessageRequestHeader(); + header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); + header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); + String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) + ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); + header.setLanguage(lan); + header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); + header.setRegion(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.REGION)); + header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); + header.setDcn(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.DCN)); + header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); + header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); + header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); + header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); + header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); + return header; + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.LANGUAGE, language); + map.put(ProtocolKey.VERSION, version); + map.put(ProtocolKey.ClientInstanceKey.ENV, env); + map.put(ProtocolKey.ClientInstanceKey.REGION, region); + map.put(ProtocolKey.ClientInstanceKey.IDC, idc); + map.put(ProtocolKey.ClientInstanceKey.DCN, dcn); + map.put(ProtocolKey.ClientInstanceKey.SYS, sys); + map.put(ProtocolKey.ClientInstanceKey.PID, pid); + map.put(ProtocolKey.ClientInstanceKey.IP, ip); + map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); + map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); + return map; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageRequestHeader={") + .append("code=").append(code).append(",") + .append("language=").append(language).append(",") + .append("version=").append(version).append(",") + .append("env=").append(env).append(",") + .append("region=").append(region).append(",") + .append("idc=").append(idc).append(",") + .append("dcn=").append(dcn).append(",") + .append("sys=").append(sys).append(",") + .append("pid=").append(pid).append(",") + .append("ip=").append(ip).append(",") + .append("username=").append(username).append(",") + .append("passwd=").append(passwd).append("}"); + return sb.toString(); + } + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageResponseHeader.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageResponseHeader.java new file mode 100644 index 0000000000..3e807e9a4f --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/http/header/message/SendMessageResponseHeader.java @@ -0,0 +1,146 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.http.header.message; + + +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.header.Header; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageResponseHeader extends Header { + + //响应码, 与对应Request的code一致 + private int code; + + //处理该次Request请求的proxy的集群名 + private String proxyCluster; + + //处理该次Request请求的proxy的IP + private String proxyIp; + + //处理该次Request请求的proxy所在的环境编号 + private String proxyEnv; + + //处理该次Request请求的proxy所在区域 + private String proxyRegion; + + //处理该次Request请求的proxy所在IDC + private String proxyIdc; + + //处理该次Request请求的proxy所在DCN + private String proxyDcn; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getProxyCluster() { + return proxyCluster; + } + + public void setProxyCluster(String proxyCluster) { + this.proxyCluster = proxyCluster; + } + + public String getProxyIp() { + return proxyIp; + } + + public void setProxyIp(String proxyIp) { + this.proxyIp = proxyIp; + } + + public String getProxyEnv() { + return proxyEnv; + } + + public void setProxyEnv(String proxyEnv) { + this.proxyEnv = proxyEnv; + } + + public String getProxyRegion() { + return proxyRegion; + } + + public void setProxyRegion(String proxyRegion) { + this.proxyRegion = proxyRegion; + } + + public String getProxyIdc() { + return proxyIdc; + } + + public void setProxyIdc(String proxyIdc) { + this.proxyIdc = proxyIdc; + } + + public String getProxyDcn() { + return proxyDcn; + } + + public void setProxyDcn(String proxyDcn) { + this.proxyDcn = proxyDcn; + } + + public static SendMessageResponseHeader buildHeader(Integer requestCode, String proxyCluster, + String proxyIp, String proxyEnv, String proxyRegion, + String proxyDcn, String proxyIDC) { + SendMessageResponseHeader sendMessageResponseHeader = new SendMessageResponseHeader(); + sendMessageResponseHeader.setCode(requestCode); + sendMessageResponseHeader.setProxyCluster(proxyCluster); + sendMessageResponseHeader.setProxyDcn(proxyDcn); + sendMessageResponseHeader.setProxyIp(proxyIp); + sendMessageResponseHeader.setProxyEnv(proxyEnv); + sendMessageResponseHeader.setProxyRegion(proxyRegion); + sendMessageResponseHeader.setProxyIdc(proxyIDC); + return sendMessageResponseHeader; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageResponseHeader={") + .append("code=").append(code).append(",") + .append("proxyEnv=").append(proxyEnv).append(",") + .append("proxyRegion=").append(proxyRegion).append(",") + .append("proxyIdc=").append(proxyIdc).append(",") + .append("proxyDcn=").append(proxyDcn).append(",") + .append("proxyCluster=").append(proxyCluster).append(",") + .append("proxyIp=").append(proxyIp).append("}"); + return sb.toString(); + } + + @Override + public Map toMap() { + Map map = new HashMap(); + map.put(ProtocolKey.REQUEST_CODE, code); + map.put(ProtocolKey.ProxyInstanceKey.PROXYCLUSTER, proxyCluster); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIP, proxyIp); + map.put(ProtocolKey.ProxyInstanceKey.PROXYENV, proxyEnv); + map.put(ProtocolKey.ProxyInstanceKey.PROXYREGION, proxyRegion); + map.put(ProtocolKey.ProxyInstanceKey.PROXYIDC, proxyIdc); + map.put(ProtocolKey.ProxyInstanceKey.PROXYDCN, proxyDcn); + return map; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/AccessMessage.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/AccessMessage.java new file mode 100644 index 0000000000..9a096c3802 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/AccessMessage.java @@ -0,0 +1,71 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.tcp; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class EventMeshMessage { + + private String topic; + Map properties = new ConcurrentHashMap<>(); + private String body; + + public EventMeshMessage() { + } + + public EventMeshMessage(String topic, Map properties, String body) { + this.topic = topic; + this.properties = properties; + this.body = body; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + @Override + public String toString() { + return "AccessMessage{" + + "topic='" + topic + '\'' + + ", properties=" + properties + + '}'; + } + + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Command.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Command.java new file mode 100644 index 0000000000..9af620cac9 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Command.java @@ -0,0 +1,105 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.tcp; + +public enum Command { + + //心跳 + HEARTBEAT_REQUEST(0), //client发给server的心跳包 + HEARTBEAT_RESPONSE(1), //server回复client的心跳包 + + //握手 + HELLO_REQUEST(2), //client发给server的握手请求 + HELLO_RESPONSE(3), //server回复client的握手请求 + + //断连 + CLIENT_GOODBYE_REQUEST(4), //client主动断连时通知server + CLIENT_GOODBYE_RESPONSE(5), //server回复client的主动断连通知 + SERVER_GOODBYE_REQUEST(6), //server主动断连时通知client + SERVER_GOODBYE_RESPONSE(7), //client回复server的主动断连通知 + + //订阅管理 + SUBSCRIBE_REQUEST(8), //client发给server的订阅请求 + SUBSCRIBE_RESPONSE(9), //server回复client的订阅请求 + UNSUBSCRIBE_REQUEST(10), //client发给server的取消订阅请求 + UNSUBSCRIBE_RESPONSE(11), //server回复client的取消订阅请求 + + //监听 + LISTEN_REQUEST(12), //client发给server的启动topic监听的请求 + LISTEN_RESPONSE(13), //server回复client的监听请求 + + //RR + REQUEST_TO_SERVER(14), //client将RR请求发送给server + REQUEST_TO_CLIENT(15), //server将RR请求推送给client + REQUEST_TO_CLIENT_ACK(16), //client收到RR请求后ACK给server + RESPONSE_TO_SERVER(17), //client将RR回包发送给server + RESPONSE_TO_CLIENT(18), //server将RR回包推送给client + RESPONSE_TO_CLIENT_ACK(19), //client收到回包后ACK给server + + //异步事件 + ASYNC_MESSAGE_TO_SERVER(20), //client将异步事件发送给server + ASYNC_MESSAGE_TO_SERVER_ACK(21), //server收到异步事件后ACK给client + ASYNC_MESSAGE_TO_CLIENT(22), //server将异步事件推送给client + ASYNC_MESSAGE_TO_CLIENT_ACK(23), //client收到异步事件后ACK给server + + //广播 + BROADCAST_MESSAGE_TO_SERVER(24), //client将广播消息发送给server + BROADCAST_MESSAGE_TO_SERVER_ACK(25), //server收到广播消息后ACK给client + BROADCAST_MESSAGE_TO_CLIENT(26), //server将广播消息推送给client + BROADCAST_MESSAGE_TO_CLIENT_ACK(27), //client收到广播消息后ACK给server + + //日志上报 + SYS_LOG_TO_LOGSERVER(28), //业务日志上报 + + //RMB跟踪日志上报 + TRACE_LOG_TO_LOGSERVER(29), //RMB跟踪日志上报 + + //重定向指令 + REDIRECT_TO_CLIENT(30), //server将重定向指令推动给client + + //服务注册 + REGISTER_REQUEST(31), //client发送注册请求给server + REGISTER_RESPONSE(32), //server将注册结果给client + + //服务去注册 + UNREGISTER_REQUEST(33), //client发送去注册请求给server + UNREGISTER_RESPONSE(34), //server将去注册结果给client + + //client询问proxy推荐连哪个proxy + RECOMMEND_REQUEST(35), //client发送推荐请求给server + RECOMMEND_RESPONSE(36); //server将推荐结果给client + + private final byte value; + + Command(int value) { + this.value = (byte) value; + } + + public byte value() { + return this.value; + } + + public static Command valueOf(int value) { + for (Command t : Command.values()) { + if (t.value == value) { + return t; + } + } + throw new IllegalArgumentException("No enum constant value=" + value); + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Header.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Header.java new file mode 100644 index 0000000000..7d1fdd06cd --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Header.java @@ -0,0 +1,78 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.tcp; + +public class Header { + + private Command cmd; + private int code; + private String msg; + private String seq; + + public Header() { + } + + public Header(Command cmd, int code, String msg, String seq) { + this.cmd = cmd; + this.code = code; + this.msg = msg; + this.seq = seq; + } + + public Command getCommand() { + return cmd; + } + + public void setCommand(Command cmd) { + this.cmd = cmd; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getSeq() { + return seq; + } + + public void setSeq(String seq) { + this.seq = seq; + } + + @Override + public String toString() { + return "Header{" + + "cmd=" + cmd + + ", code=" + code + + ", msg='" + msg + '\'' + + ", seq='" + seq + '\'' + + '}'; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/HeartBeatInfo.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/HeartBeatInfo.java new file mode 100644 index 0000000000..2026b8030d --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/HeartBeatInfo.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.webank.eventmesh.common.protocol.tcp; + +import java.util.List; + +public class HeartBeatInfo { + + private String serviceId; + + private String instanceId; + + private List topicList; + + public HeartBeatInfo() { + } + + public HeartBeatInfo(List topicList) { + this.topicList = topicList; + } + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public List getTopicList() { + return topicList; + } + + public void setTopicList(List topicList) { + this.topicList = topicList; + } + + @Override + public String toString() { + return "HeartBeatInfo{" + + "serviceId=" + serviceId + + "instanceId=" + instanceId + + "topicList=" + topicList + + '}'; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/OPStatus.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/OPStatus.java new file mode 100644 index 0000000000..cce875180a --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/OPStatus.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.webank.eventmesh.common.protocol.tcp; + +public enum OPStatus { + + SUCCESS(0, "success"), + FAIL(1, "fail"), + ACL_FAIL(2, "aclFail"), + TPS_OVERLOAD(3, "tpsOverload"); + + OPStatus(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + + private Integer code; + + private String desc; + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Package.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Package.java new file mode 100644 index 0000000000..31b4d12358 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Package.java @@ -0,0 +1,62 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.tcp; + +public class Package { + + private Header header; + private Object body; + + public Package() { + } + + public Package(Header header) { + this.header = header; + } + + public Package(Header header, Object body) { + this.header = header; + this.body = body; + } + + public Header getHeader() { + return header; + } + + public void setHeader(Header header) { + this.header = header; + } + + public Object getBody() { + return body; + } + + public void setBody(Object body) { + this.body = body; + } + + @Override + public String toString() { + return "Message{" + + "header=" + header + + ", body=" + body + + '}'; + } + + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/ProxyClientInfo.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/ProxyClientInfo.java new file mode 100644 index 0000000000..b27d54b7b8 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/ProxyClientInfo.java @@ -0,0 +1,111 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.tcp; + +import org.apache.rocketmq.common.DataVersion; + +public class ProxyClientInfo { + private String clientId; + private String consumerGroup; + private String endpoint; + private String language; + private long version; + private DataVersion dataVersion; + private long lastUpdateTimestamp; + private int protocolNumber; + + public ProxyClientInfo(String clientId, String consumerGroup, String endpoint, String language, long version, DataVersion dataVersion, long lastUpdateTimestamp, int protocolNumber) { + this.clientId = clientId; + this.endpoint = endpoint; + this.language = language; + this.version = version; + this.consumerGroup = consumerGroup; + this.dataVersion = dataVersion; + this.lastUpdateTimestamp = lastUpdateTimestamp; + this.protocolNumber = protocolNumber; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientId() { + return clientId; + } + + public void setDataVersion(DataVersion dataVersion) { + this.dataVersion = dataVersion; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public DataVersion getDataVersion() { + return dataVersion; + } + + public String getEndpoint() { + return endpoint; + } + + public void setLastUpdateTimestamp(long lastUpdateTimestamp) { + this.lastUpdateTimestamp = lastUpdateTimestamp; + } + + public long getLastUpdateTimestamp() { + return lastUpdateTimestamp; + } + + public void setConsumerGroup(String consumerGroup) { + this.consumerGroup = consumerGroup; + } + + public String getConsumerGroup() { + return consumerGroup; + } + + public void setVersion(long version) { + this.version = version; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getLanguage() { + return language; + } + + public long getVersion() { + return version; + } + + public void setProtocolNumber(int protocolNumber) { + this.protocolNumber = protocolNumber; + } + + public int getProtocolNumber() { + return protocolNumber; + } + + @Override + public String toString() { + return "ClientId [clientId=" + clientId + ", consumerGroup=" + consumerGroup + ", endpoint=" + endpoint + ", language=" + language + ", version=" + version + ", dataVersion=" + dataVersion + ", lastUpdateTimestamp=" + lastUpdateTimestamp + "]"; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/RedirectInfo.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/RedirectInfo.java new file mode 100644 index 0000000000..ea3f1654cc --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/RedirectInfo.java @@ -0,0 +1,55 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.tcp; + +public class RedirectInfo { + private String ip; + private int port; + + public RedirectInfo() { + } + + public RedirectInfo(String ip, int port) { + this.ip = ip; + this.port = port; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + @Override + public String toString() { + return "RedirectInfo{" + + "ip='" + ip + '\'' + + ", port=" + port + + '}'; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/RegisterInfo.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/RegisterInfo.java new file mode 100644 index 0000000000..725435b360 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/RegisterInfo.java @@ -0,0 +1,47 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.tcp; + +import java.util.List; + +public class RegisterInfo { + + private List topicList; + + public RegisterInfo() { + } + + public RegisterInfo(List topicList) { + this.topicList = topicList; + } + + public List getTopicList() { + return topicList; + } + + public void setTopicList(List topicList) { + this.topicList = topicList; + } + + @Override + public String toString() { + return "RegisterInfo{" + + "topicList=" + topicList + + '}'; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Subscription.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Subscription.java new file mode 100644 index 0000000000..85da1b5f92 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/Subscription.java @@ -0,0 +1,50 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.tcp; + +import java.util.LinkedList; +import java.util.List; + +public class Subscription { + + private List topicList = new LinkedList<>(); + + public Subscription() { + } + + public Subscription(List topicList) { + this.topicList = topicList; + } + + public List getTopicList() { + return topicList; + } + + public void setTopicList(List topicList) { + this.topicList = topicList; + } + + @Override + public String toString() { + return "Subscription{" + + "topicList=" + topicList + + '}'; + } + + +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/UnRegisterInfo.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/UnRegisterInfo.java new file mode 100644 index 0000000000..e293154043 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/UnRegisterInfo.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.webank.eventmesh.common.protocol.tcp; + +import java.util.List; + +public class UnRegisterInfo { + + private String serviceId; + + private String instanceId; + + private List topicList; + + public UnRegisterInfo() { + } + + public UnRegisterInfo(List topicList) { + this.topicList = topicList; + } + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public List getTopicList() { + return topicList; + } + + public void setTopicList(List topicList) { + this.topicList = topicList; + } + + @Override + public String toString() { + return "RegisterInfo{" + + "serviceId=" + serviceId + + "instanceId=" + instanceId + + "topicList=" + topicList + + '}'; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/UserAgent.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/UserAgent.java new file mode 100644 index 0000000000..987a54b23d --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/UserAgent.java @@ -0,0 +1,199 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.tcp; + +public class UserAgent { + + private String env; + private String subsystem; + private String dcn; + private String path; + private int pid; + private String host; + private int port; + private String version; + private String username; + private String password; + private String idc; + private String purpose; + private int unack = 0; + + public UserAgent() { + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getPurpose() { + return purpose; + } + + public void setPurpose(String purpose) { + this.purpose = purpose; + } + + public String getSubsystem() { + return subsystem; + } + + public void setSubsystem(String subsystem) { + this.subsystem = subsystem; + } + + public String getDcn() { + return dcn; + } + + public void setDcn(String dcn) { + this.dcn = dcn; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public int getPid() { + return pid; + } + + public void setPid(int pid) { + this.pid = pid; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public int getUnack() { + return unack; + } + + public void setUnack(int unack) { + this.unack = unack; + } + + @Override + public String toString() { + return "UserAgent{" + + "env='" + env + '\'' + + "subsystem='" + subsystem + '\'' + + ", dcn='" + dcn + '\'' + + ", path='" + path + '\'' + + ", pid=" + pid + + ", host='" + host + '\'' + + ", port=" + port + + ", version='" + version + '\'' + + ", idc='" + idc + '\'' + + ", purpose='" + purpose + '\'' + + ", unack='" + unack + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + UserAgent userAgent = (UserAgent) o; + + if (pid != userAgent.pid) return false; + if (port != userAgent.port) return false; + if (unack != userAgent.unack) return false; + if (subsystem != null ? !subsystem.equals(userAgent.subsystem) : userAgent.subsystem != null) return false; + if (dcn != null ? !dcn.equals(userAgent.dcn) : userAgent.dcn != null) return false; + if (path != null ? !path.equals(userAgent.path) : userAgent.path != null) return false; + if (host != null ? !host.equals(userAgent.host) : userAgent.host != null) return false; + if (purpose != null ? !purpose.equals(userAgent.purpose) : userAgent.purpose != null) return false; + if (version != null ? !version.equals(userAgent.version) : userAgent.version != null) return false; + if (username != null ? !username.equals(userAgent.username) : userAgent.username != null) return false; + if (password != null ? !password.equals(userAgent.password) : userAgent.password != null) return false; + if (env != null ? !env.equals(userAgent.env) : userAgent.env != null) return false; + return idc != null ? idc.equals(userAgent.idc) : userAgent.idc == null; + } + + @Override + public int hashCode() { + int result = subsystem != null ? subsystem.hashCode() : 0; + result = 31 * result + (dcn != null ? dcn.hashCode() : 0); + result = 31 * result + (path != null ? path.hashCode() : 0); + result = 31 * result + pid; + result = 31 * result + (host != null ? host.hashCode() : 0); + result = 31 * result + (purpose != null ? purpose.hashCode() : 0); + result = 31 * result + port; + result = 31 * result + (version != null ? version.hashCode() : 0); + result = 31 * result + (username != null ? username.hashCode() : 0); + result = 31 * result + (password != null ? password.hashCode() : 0); + result = 31 * result + (idc != null ? idc.hashCode() : 0); + result = 31 * result + (env != null ? env.hashCode() : 0); + result = 31 * result + unack; + return result; + } +} diff --git a/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/codec/Codec.java b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/codec/Codec.java new file mode 100644 index 0000000000..95381a37f0 --- /dev/null +++ b/eventmesh-common/src/main/java/cn/webank/eventmesh/common/protocol/tcp/codec/Codec.java @@ -0,0 +1,180 @@ +/* + * 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 cn.webank.eventmesh.common.protocol.tcp.codec; + +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.AccessMessage; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.RedirectInfo; +import cn.webank.eventmesh.common.protocol.tcp.Subscription; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import io.netty.handler.codec.ReplayingDecoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.List; +import java.util.TimeZone; + +public class Codec { + + private final static Logger logger = LoggerFactory.getLogger(Codec.class); + private static final int FRAME_MAX_LENGTH = 1024 * 1024 * 4; + private static Charset UTF8 = Charset.forName("UTF-8"); + + private static final byte[] CONSTANT_MAGIC_FLAG = "WEMQ".getBytes(UTF8); + + private static final byte[] VERSION = "0000".getBytes(UTF8); + + private static ObjectMapper jsonMapper; + + static { + jsonMapper = new ObjectMapper(); + jsonMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + jsonMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + jsonMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + jsonMapper.setTimeZone(TimeZone.getDefault()); + } + + public static class Encoder extends MessageToByteEncoder { + @Override + public void encode(ChannelHandlerContext ctx, Package pkg, ByteBuf out) throws Exception { + byte[] headerData; + byte[] bodyData; + + final String headerJson = pkg != null ? jsonMapper.writeValueAsString(pkg.getHeader()) : null; + final String bodyJson = pkg != null ? jsonMapper.writeValueAsString(pkg.getBody()) : null; + + headerData = headerJson == null ? null : headerJson.getBytes(UTF8); + bodyData = bodyJson == null ? null : bodyJson.getBytes(UTF8); + + logger.debug("headerJson={}|bodyJson={}", headerJson, bodyJson); + + int headerLength = headerData == null ? 0 : headerData.length; + int bodyLength = bodyData == null ? 0 : bodyData.length; + + int length = 4 + 4 + headerLength + bodyLength; + + if (length > FRAME_MAX_LENGTH) { + throw new IllegalArgumentException("message size is exceed limit!"); + } + + out.writeBytes(CONSTANT_MAGIC_FLAG); + out.writeBytes(VERSION); + out.writeInt(length); + out.writeInt(headerLength); + if (headerData != null) + out.writeBytes(headerData); + if (bodyData != null) + out.writeBytes(bodyData); + } + } + + public static class Decoder extends ReplayingDecoder { + @Override + public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + Header header = null; + Object body = null; + + int length = 0; + int headerLength = 0; + int bodyLength = 0; + + try { + if (null == in) + return; + + byte[] flagBytes = new byte[CONSTANT_MAGIC_FLAG.length]; + byte[] versionBytes = new byte[VERSION.length]; + + in.readBytes(flagBytes); + in.readBytes(versionBytes); + if (!Arrays.equals(flagBytes, CONSTANT_MAGIC_FLAG) || !Arrays.equals(versionBytes, VERSION)) { + String errorMsg = String.format("invalid magic flag or " + + "version|flag=%s|version=%s|remoteAddress=%s", new String(flagBytes, UTF8), new String + (versionBytes, UTF8), ctx.channel().remoteAddress()); + throw new Exception(errorMsg); + } + + length = in.readInt(); + headerLength = in.readInt(); + bodyLength = length - 8 - headerLength; + byte[] headerData = new byte[headerLength]; + byte[] bodyData = new byte[bodyLength]; + + if (headerLength > 0) { + in.readBytes(headerData); + header = jsonMapper.readValue(new String(headerData, UTF8), Header.class); + } + + if (bodyLength > 0 && header != null) { + in.readBytes(bodyData); + body = parseFromJson(header.getCommand(), new String(bodyData, UTF8)); + } + + logger.debug("headerJson={}|bodyJson={}", new String(headerData, UTF8), new String(bodyData, UTF8)); + + Package pkg = new Package(header, body); + out.add(pkg); + } catch (Exception e) { + logger.error("decode|length={}|headerLength={}|bodyLength={}|header={}|body={}.", length, + headerLength, bodyLength, header, body); + throw e; + } + } + } + + private static Object parseFromJson(Command cmd, String data) throws Exception { + switch (cmd) { + case HELLO_REQUEST: + case RECOMMEND_REQUEST: + return jsonMapper.readValue(data, UserAgent.class); + case SUBSCRIBE_REQUEST: + case UNSUBSCRIBE_REQUEST: + return jsonMapper.readValue(data, Subscription.class); + case REQUEST_TO_SERVER: + case RESPONSE_TO_SERVER: + case ASYNC_MESSAGE_TO_SERVER: + case BROADCAST_MESSAGE_TO_SERVER: + return jsonMapper.readValue(data, AccessMessage.class); + case REQUEST_TO_CLIENT: + case RESPONSE_TO_CLIENT: + case ASYNC_MESSAGE_TO_CLIENT: + case BROADCAST_MESSAGE_TO_CLIENT: + return jsonMapper.readValue(data, AccessMessage.class); + case REQUEST_TO_CLIENT_ACK: + case RESPONSE_TO_CLIENT_ACK: + case ASYNC_MESSAGE_TO_CLIENT_ACK: + case BROADCAST_MESSAGE_TO_CLIENT_ACK: + return jsonMapper.readValue(data, AccessMessage.class); + case REDIRECT_TO_CLIENT: + return jsonMapper.readValue(data, RedirectInfo.class); + default: + return null; + } + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/NetUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/NetUtils.java index 2683deaa84..92492fd200 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/NetUtils.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/NetUtils.java @@ -72,6 +72,10 @@ public static String addressToString(Collection clients) { for (InetSocketAddress addr : clients) { sb.append(addr).append(Constants.VERTICAL_LINE); } + // remove last '|' character + if (sb.length() > 0) { + return sb.substring(0, sb.length() - 1); + } return sb.toString(); } } diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/consumer/StandaloneConsumerAdaptor.java b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/consumer/StandaloneConsumerAdaptor.java new file mode 100644 index 0000000000..56518a75d2 --- /dev/null +++ b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/consumer/StandaloneConsumerAdaptor.java @@ -0,0 +1,172 @@ +/* + * 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.connector.standalone.consumer; + +import org.apache.eventmesh.api.AbstractContext; +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.consumer.Consumer; + +import java.util.List; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.cloudevents.CloudEvent; + +public class StandaloneConsumerAdaptor implements Consumer { + + private final Logger logger = LoggerFactory.getLogger(StandaloneConsumerAdaptor.class); + + private StandaloneConsumer consumer; + + public StandaloneConsumerAdaptor() { + } + + @Override + public boolean isStarted() { + return false; + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public void start() { + + } + + @Override + public void shutdown() { + + } + + @Override + public void init(Properties keyValue) throws Exception { + + } + + @Override + public void updateOffset(List cloudEvents, AbstractContext context) { + + } + + @Override + public void subscribe(String topic, EventListener listener) throws Exception { + + } + + @Override + public void unsubscribe(String topic) { + + } + +// @Override +// public void init(Properties keyValue) throws Exception { +// String producerGroup = keyValue.getProperty("producerGroup"); +// +// MessagingAccessPointImpl messagingAccessPoint = new MessagingAccessPointImpl(keyValue); +// consumer = (StandaloneConsumer) messagingAccessPoint.createConsumer(keyValue); +// +// } +// +// @Override +// public void updateOffset(List msgs, AbstractContext context) { +// for(Message message : msgs) { +// consumer.updateOffset(message); +// } +// } +// +// @Override +// public void subscribe(String topic, AsyncMessageListener listener) throws Exception { +// // todo: support subExpression +// consumer.subscribe(topic, "*", listener); +// } +// +// @Override +// public void unsubscribe(String topic) { +// consumer.unsubscribe(topic); +// } +// +// @Override +// public void subscribe(String topic, String subExpression, MessageListener listener) { +// throw new UnsupportedOperationException("not supported yet"); +// } +// +// @Override +// public void subscribe(String topic, MessageSelector selector, MessageListener listener) { +// throw new UnsupportedOperationException("not supported yet"); +// } +// +// @Override +// public void subscribe(String topic, String subExpression, GenericMessageListener listener) { +// throw new UnsupportedOperationException("not supported yet"); +// } +// +// @Override +// public void subscribe(String topic, MessageSelector selector, GenericMessageListener listener) { +// throw new UnsupportedOperationException("not supported yet"); +// } +// +// @Override +// public void subscribe(String topic, String subExpression, AsyncMessageListener listener) { +// throw new UnsupportedOperationException("not supported yet"); +// } +// +// @Override +// public void subscribe(String topic, MessageSelector selector, AsyncMessageListener listener) { +// throw new UnsupportedOperationException("not supported yet"); +// } +// +// @Override +// public void subscribe(String topic, String subExpression, AsyncGenericMessageListener listener) { +// throw new UnsupportedOperationException("not supported yet"); +// } +// +// @Override +// public void subscribe(String topic, MessageSelector selector, AsyncGenericMessageListener listener) { +// throw new UnsupportedOperationException("not supported yet"); +// } +// +// @Override +// public void updateCredential(Properties credentialProperties) { +// +// } +// +// @Override +// public boolean isStarted() { +// return consumer.isStarted(); +// } +// +// @Override +// public boolean isClosed() { +// return consumer.isClosed(); +// } +// +// @Override +// public void start() { +// consumer.start(); +// } +// +// @Override +// public void shutdown() { +// consumer.shutdown(); +// } +} diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/producer/StandaloneProducerAdaptor.java b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/producer/StandaloneProducerAdaptor.java new file mode 100644 index 0000000000..d60968cafc --- /dev/null +++ b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/producer/StandaloneProducerAdaptor.java @@ -0,0 +1,112 @@ +/* + * 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.connector.standalone.producer; + +import org.apache.eventmesh.api.RRCallback; +import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.producer.Producer; + +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.cloudevents.CloudEvent; + +public class StandaloneProducerAdaptor implements Producer { + + private final Logger logger = LoggerFactory.getLogger(StandaloneProducerAdaptor.class); + + private StandaloneProducer standaloneProducer; + + public StandaloneProducerAdaptor() { + } + + @Override + public boolean isStarted() { + return standaloneProducer.isStarted(); + } + + @Override + public boolean isClosed() { + return standaloneProducer.isClosed(); + } + + @Override + public void start() { + standaloneProducer.start(); + } + + @Override + public void shutdown() { + standaloneProducer.shutdown(); + } + + @Override + public void init(Properties properties) throws Exception { + standaloneProducer.init(properties); + } + + @Override + public SendResult publish(CloudEvent cloudEvent) { + return standaloneProducer.publish(cloudEvent); + } + + @Override + public void publish(CloudEvent cloudEvent, SendCallback sendCallback) throws Exception { + standaloneProducer.publish(cloudEvent, sendCallback); + } + + @Override + public void sendOneway(CloudEvent cloudEvent) { + standaloneProducer.sendOneway(cloudEvent); + } + + @Override + public void sendAsync(CloudEvent cloudEvent, SendCallback sendCallback) { + standaloneProducer.sendAsync(cloudEvent, sendCallback); + } + + @Override + public void request(CloudEvent cloudEvent, RRCallback rrCallback, long timeout) throws Exception { + standaloneProducer.request(cloudEvent, rrCallback, timeout); + } + + @Override + public void request(CloudEvent cloudEvent, RequestReplyCallback rrCallback, long timeout) throws Exception { + standaloneProducer.request(cloudEvent, rrCallback, timeout); + } + + @Override + public boolean reply(CloudEvent cloudEvent, SendCallback sendCallback) throws Exception { + return standaloneProducer.reply(cloudEvent, sendCallback); + } + + @Override + public void checkTopicExist(String topic) throws Exception { + standaloneProducer.checkTopicExist(topic); + } + + @Override + public void setExtFields() { + standaloneProducer.setExtFields(); + } + +} diff --git a/eventmesh-connector-rocketmq/build.gradle b/eventmesh-connector-rocketmq/build.gradle new file mode 100644 index 0000000000..3f9f23a3e1 --- /dev/null +++ b/eventmesh-connector-rocketmq/build.gradle @@ -0,0 +1,158 @@ +import java.util.concurrent.TimeUnit + +apply plugin: 'java' +apply plugin: "maven" +apply plugin: "eclipse" +apply plugin: "idea" + +sourceCompatibility = 1.8 + +configurations { + compile.exclude group: 'ch.qos.logback', module: 'logback-classic' +} +repositories { + mavenLocal() + maven { + url "https://maven.aliyun.com/repository/public" + } + mavenCentral() +} + +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", + +] + +List junit = [ + "junit:junit:4.12" +] + +List log4j2 = [ + "org.apache.logging.log4j:log4j-api:2.13.3", + "org.apache.logging.log4j:log4j-core:2.13.3", + "org.apache.logging.log4j:log4j-slf4j-impl:2.13.3", + "org.apache.logging.log4j:log4j-web:2.13.3", + "com.lmax:disruptor:3.4.2" +] + +List sl4j = [ + "org.slf4j:slf4j-api:1.7.30" +] + +List metrics = [ + "io.dropwizard.metrics:metrics-core:4.1.0", + "io.dropwizard.metrics:metrics-healthchecks:4.1.0", + "io.dropwizard.metrics:metrics-annotation:4.1.0", + "io.dropwizard.metrics:metrics-json:4.1.0" +] + +dependencies { + compile project(":eventmesh-runtime") + testCompile project(":eventmesh-runtime") + compile rocketmq, metrics, log4j2, sl4j + testCompile rocketmq, metrics, log4j2, sl4j, junit +} + +clean.doFirst { + delete 'build' + delete 'dist' +} + +//def versionString = project.version +//if (project.findProperty("buildNo") instanceof String) { +// versionString = project.version + '_' + project.property("buildNo") +//} + +//task zip(type: Zip, dependsOn: ['clean', 'jar']) { +// extension = 'zip' +// archiveName = project.name + '_' + versionString + '.' + extension +// destinationDir = new File(projectDir, 'dist') +// +// into('apps') { +// from project.jar.getArchivePath() +// } +// +// into('bin') { +// from 'bin' +// } +// +// into('conf') { +// from "conf" +// } +// +// into('lib') { +// from project.configurations.runtime +// exclude '**/*.properties*' +// exclude '**/*testng*.jar' +// exclude '**/*powermock*.jar' +// exclude '**/*mockito*.jar' +// exclude '**/*junit*.jar' +// exclude '**/*jacoco*.jar' +// exclude '**/*log4j2.xml*' +// exclude '**/spring-boot-devtools*.jar' +// } +// +// into('scripts') { +// from "scripts" +// } +//} +// +//task tar(type: Tar, dependsOn: ['clean', 'jar']) { +// extension = 'tar.gz' +// compression = Compression.GZIP +// archiveName = project.name + '_' + versionString + '.' + extension +// destinationDir = new File(projectDir, 'dist') +// +// into('apps') { +// from project.jar.getArchivePath() +// } +// +// into('bin') { +// from 'bin' +// } +// +// into('conf') { +// from "conf" +// } +// +// into('lib') { +// from project.configurations.runtime +// exclude '**/*.properties*' +// exclude '**/*testng*.jar' +// exclude '**/*powermock*.jar' +// exclude '**/*mockito*.jar' +// exclude '**/*junit*.jar' +// exclude '**/*jacoco*.jar' +// exclude '**/*log4j2.xml*' +// exclude '**/spring-boot-devtools*.jar' +// } +// +// into('scripts') { +// from "scripts" +// } +//} + +//uploadArchives { +// repositories { +// mavenDeployer { +// snapshotRepository(url: 'Your target repo address') { +// authentication(userName: 'Your user name', password: 'Your password') +// } +// repository(url: 'Your target repo address') { +// authentication(userName: 'Your user name', password: 'Your password') +// } +// } +// } +//} \ No newline at end of file diff --git a/eventmesh-connector-rocketmq/gradle.properties b/eventmesh-connector-rocketmq/gradle.properties new file mode 100644 index 0000000000..154974205a --- /dev/null +++ b/eventmesh-connector-rocketmq/gradle.properties @@ -0,0 +1,23 @@ +# +# 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. +# + +group=com.webank.eventmesh +version=1.1.1 +defibus_version=1.0.1 +rocketmq_version=4.7.1 +mavenUserName= +mavenPassword= \ No newline at end of file diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/MessagingAccessPointImpl.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/MessagingAccessPointImpl.java new file mode 100644 index 0000000000..d388821289 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/MessagingAccessPointImpl.java @@ -0,0 +1,104 @@ +/* + * 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 connector.rocketmq; + +import connector.rocketmq.consumer.PullConsumerImpl; +import connector.rocketmq.consumer.PushConsumerImpl; +import connector.rocketmq.producer.ProducerImpl; +import connector.rocketmq.utils.OMSUtil; +import io.openmessaging.KeyValue; +import io.openmessaging.MessagingAccessPoint; +import io.openmessaging.ResourceManager; +import io.openmessaging.consumer.PullConsumer; +import io.openmessaging.consumer.PushConsumer; +import io.openmessaging.consumer.StreamingConsumer; +import io.openmessaging.exception.OMSNotSupportedException; +import io.openmessaging.producer.Producer; + +public class MessagingAccessPointImpl implements MessagingAccessPoint { + + private KeyValue accessPointProperties; + + public MessagingAccessPointImpl(final KeyValue accessPointProperties) { + this.accessPointProperties = accessPointProperties; + } + + @Override + public KeyValue attributes() { + return accessPointProperties; + } + + @Override + public String implVersion() { + return "0.3.0"; + } + + @Override + public Producer createProducer() { + return new ProducerImpl(this.accessPointProperties); + } + + @Override + public Producer createProducer(KeyValue properties) { + return new ProducerImpl(OMSUtil.buildKeyValue(this.accessPointProperties, properties)); + } + + @Override + public PushConsumer createPushConsumer() { + return new PushConsumerImpl(accessPointProperties); + } + + @Override + public PushConsumer createPushConsumer(KeyValue properties) { + return new PushConsumerImpl(OMSUtil.buildKeyValue(this.accessPointProperties, properties)); + } + + @Override + public PullConsumer createPullConsumer() { + return new PullConsumerImpl(accessPointProperties); + } + + @Override + public PullConsumer createPullConsumer(KeyValue attributes) { + return new PullConsumerImpl(OMSUtil.buildKeyValue(this.accessPointProperties, attributes)); + } + + @Override + public StreamingConsumer createStreamingConsumer() { + return null; + } + + @Override + public StreamingConsumer createStreamingConsumer(KeyValue attributes) { + return null; + } + + @Override + public ResourceManager resourceManager() { + throw new OMSNotSupportedException("-1", "ResourceManager is not supported in current version."); + } + + @Override + public void startup() { + //Ignore + } + + @Override + public void shutdown() { + //Ignore + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/config/ClientConfig.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/config/ClientConfig.java new file mode 100644 index 0000000000..d44a2b6358 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/config/ClientConfig.java @@ -0,0 +1,194 @@ +/* + * 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 connector.rocketmq.config; + +import connector.rocketmq.domain.NonStandardKeys; +import io.openmessaging.OMSBuiltinKeys; + +public class ClientConfig implements OMSBuiltinKeys, NonStandardKeys { + private String driverImpl; + private String accessPoints; + private String namespace; + private String producerId; + private String consumerId; + private int operationTimeout = 5000; + private String region; + private String routingSource; + private String routingDestination; + private String routingExpression; + private String rmqConsumerGroup; + private String rmqProducerGroup = "__OMS_PRODUCER_DEFAULT_GROUP"; + private int rmqMaxRedeliveryTimes = 16; + private int rmqMessageConsumeTimeout = 15; //In minutes + private int rmqMaxConsumeThreadNums = 64; + private int rmqMinConsumeThreadNums = 20; + private String rmqMessageDestination; + private int rmqPullMessageBatchNums = 32; + private int rmqPullMessageCacheCapacity = 1000; + + public String getDriverImpl() { + return driverImpl; + } + + public void setDriverImpl(final String driverImpl) { + this.driverImpl = driverImpl; + } + + public String getAccessPoints() { + return accessPoints; + } + + public void setAccessPoints(final String accessPoints) { + this.accessPoints = accessPoints; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(final String namespace) { + this.namespace = namespace; + } + + public String getProducerId() { + return producerId; + } + + public void setProducerId(final String producerId) { + this.producerId = producerId; + } + + public String getConsumerId() { + return consumerId; + } + + public void setConsumerId(final String consumerId) { + this.consumerId = consumerId; + } + + public int getOperationTimeout() { + return operationTimeout; + } + + public void setOperationTimeout(final int operationTimeout) { + this.operationTimeout = operationTimeout; + } + + public String getRoutingSource() { + return routingSource; + } + + public void setRoutingSource(final String routingSource) { + this.routingSource = routingSource; + } + + public String getRmqConsumerGroup() { + return rmqConsumerGroup; + } + + public void setRmqConsumerGroup(final String rmqConsumerGroup) { + this.rmqConsumerGroup = rmqConsumerGroup; + } + + public String getRmqProducerGroup() { + return rmqProducerGroup; + } + + public void setRmqProducerGroup(final String rmqProducerGroup) { + this.rmqProducerGroup = rmqProducerGroup; + } + + public int getRmqMaxRedeliveryTimes() { + return rmqMaxRedeliveryTimes; + } + + public void setRmqMaxRedeliveryTimes(final int rmqMaxRedeliveryTimes) { + this.rmqMaxRedeliveryTimes = rmqMaxRedeliveryTimes; + } + + public int getRmqMessageConsumeTimeout() { + return rmqMessageConsumeTimeout; + } + + public void setRmqMessageConsumeTimeout(final int rmqMessageConsumeTimeout) { + this.rmqMessageConsumeTimeout = rmqMessageConsumeTimeout; + } + + public int getRmqMaxConsumeThreadNums() { + return rmqMaxConsumeThreadNums; + } + + public void setRmqMaxConsumeThreadNums(final int rmqMaxConsumeThreadNums) { + this.rmqMaxConsumeThreadNums = rmqMaxConsumeThreadNums; + } + + public int getRmqMinConsumeThreadNums() { + return rmqMinConsumeThreadNums; + } + + public void setRmqMinConsumeThreadNums(final int rmqMinConsumeThreadNums) { + this.rmqMinConsumeThreadNums = rmqMinConsumeThreadNums; + } + + public String getRmqMessageDestination() { + return rmqMessageDestination; + } + + public void setRmqMessageDestination(final String rmqMessageDestination) { + this.rmqMessageDestination = rmqMessageDestination; + } + + public int getRmqPullMessageBatchNums() { + return rmqPullMessageBatchNums; + } + + public void setRmqPullMessageBatchNums(final int rmqPullMessageBatchNums) { + this.rmqPullMessageBatchNums = rmqPullMessageBatchNums; + } + + public int getRmqPullMessageCacheCapacity() { + return rmqPullMessageCacheCapacity; + } + + public void setRmqPullMessageCacheCapacity(final int rmqPullMessageCacheCapacity) { + this.rmqPullMessageCacheCapacity = rmqPullMessageCacheCapacity; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getRoutingDestination() { + return routingDestination; + } + + public void setRoutingDestination(String routingDestination) { + this.routingDestination = routingDestination; + } + + public String getRoutingExpression() { + return routingExpression; + } + + public void setRoutingExpression(String routingExpression) { + this.routingExpression = routingExpression; + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/config/PropInitImpl.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/config/PropInitImpl.java new file mode 100644 index 0000000000..6e927824a5 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/config/PropInitImpl.java @@ -0,0 +1,16 @@ +package connector.rocketmq.config; + +import com.webank.runtime.configuration.PropInit; +import io.openmessaging.KeyValue; +import io.openmessaging.OMS; +import io.openmessaging.OMSBuiltinKeys; + +public class PropInitImpl implements PropInit { + + public final String DEFAULT_ACCESS_DRIVER = "connector.rocketmq.MessagingAccessPointImpl"; + + @Override + public KeyValue initProp() { + return OMS.newKeyValue().put(OMSBuiltinKeys.DRIVER_IMPL, DEFAULT_ACCESS_DRIVER); + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/LocalMessageCache.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/LocalMessageCache.java new file mode 100644 index 0000000000..573bb16b94 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/LocalMessageCache.java @@ -0,0 +1,209 @@ +/* + * 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 connector.rocketmq.consumer; + +import connector.rocketmq.config.ClientConfig; +import connector.rocketmq.domain.ConsumeRequest; +import io.openmessaging.KeyValue; +import io.openmessaging.Message; +import io.openmessaging.ServiceLifecycle; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.impl.consumer.ProcessQueue; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.common.ThreadFactoryImpl; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.utils.ThreadUtils; +import org.apache.rocketmq.logging.InternalLogger; + +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.*; +import java.util.concurrent.locks.ReadWriteLock; + +public class LocalMessageCache implements ServiceLifecycle { + private final BlockingQueue consumeRequestCache; + private final Map consumedRequest; + private final ConcurrentHashMap pullOffsetTable; + private final DefaultMQPullConsumer rocketmqPullConsumer; + private final ClientConfig clientConfig; + private final ScheduledExecutorService cleanExpireMsgExecutors; + + private final static InternalLogger log = ClientLogger.getLog(); + + public LocalMessageCache(final DefaultMQPullConsumer rocketmqPullConsumer, final ClientConfig clientConfig) { + consumeRequestCache = new LinkedBlockingQueue<>(clientConfig.getRmqPullMessageCacheCapacity()); + this.consumedRequest = new ConcurrentHashMap<>(); + this.pullOffsetTable = new ConcurrentHashMap<>(); + this.rocketmqPullConsumer = rocketmqPullConsumer; + this.clientConfig = clientConfig; + this.cleanExpireMsgExecutors = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl( + "OMS_CleanExpireMsgScheduledThread_")); + } + + public int nextPullBatchNums() { + return Math.min(clientConfig.getRmqPullMessageBatchNums(), consumeRequestCache.remainingCapacity()); + } + + public long nextPullOffset(MessageQueue remoteQueue) { + if (!pullOffsetTable.containsKey(remoteQueue)) { + try { + pullOffsetTable.putIfAbsent(remoteQueue, + rocketmqPullConsumer.fetchConsumeOffset(remoteQueue, false)); + } catch (MQClientException e) { + log.error("An error occurred in fetch consume offset process.", e); + } + } + return pullOffsetTable.get(remoteQueue); + } + + public void updatePullOffset(MessageQueue remoteQueue, long nextPullOffset) { + pullOffsetTable.put(remoteQueue, nextPullOffset); + } + + public void submitConsumeRequest(ConsumeRequest consumeRequest) { + try { + consumeRequestCache.put(consumeRequest); + } catch (InterruptedException ignore) { + } + } + + public MessageExt poll() { + return poll(clientConfig.getOperationTimeout()); + } + + MessageExt poll(final KeyValue properties) { + int currentPollTimeout = clientConfig.getOperationTimeout(); + if (properties.containsKey(Message.BuiltinKeys.TIMEOUT)) { + currentPollTimeout = properties.getInt(Message.BuiltinKeys.TIMEOUT); + } + return poll(currentPollTimeout); + } + + private MessageExt poll(long timeout) { + try { + ConsumeRequest consumeRequest = consumeRequestCache.poll(timeout, TimeUnit.MILLISECONDS); + if (consumeRequest != null) { + MessageExt messageExt = consumeRequest.getMessageExt(); + consumeRequest.setStartConsumeTimeMillis(System.currentTimeMillis()); + MessageAccessor.setConsumeStartTimeStamp(messageExt, String.valueOf(consumeRequest.getStartConsumeTimeMillis())); + consumedRequest.put(messageExt.getMsgId(), consumeRequest); + return messageExt; + } + } catch (InterruptedException ignore) { + } + return null; + } + + void ack(final String messageId) { + ConsumeRequest consumeRequest = consumedRequest.remove(messageId); + if (consumeRequest != null) { + long offset = consumeRequest.getProcessQueue().removeMessage(Collections.singletonList(consumeRequest.getMessageExt())); + try { + rocketmqPullConsumer.updateConsumeOffset(consumeRequest.getMessageQueue(), offset); + } catch (MQClientException e) { + log.error("An error occurred in update consume offset process.", e); + } + } + } + + void ack(final MessageQueue messageQueue, final ProcessQueue processQueue, final MessageExt messageExt) { + consumedRequest.remove(messageExt.getMsgId()); + long offset = processQueue.removeMessage(Collections.singletonList(messageExt)); + try { + rocketmqPullConsumer.updateConsumeOffset(messageQueue, offset); + } catch (MQClientException e) { + log.error("An error occurred in update consume offset process.", e); + } + } + + @Override + public void startup() { + this.cleanExpireMsgExecutors.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + cleanExpireMsg(); + } + }, clientConfig.getRmqMessageConsumeTimeout(), clientConfig.getRmqMessageConsumeTimeout(), TimeUnit.MINUTES); + } + + @Override + public void shutdown() { + ThreadUtils.shutdownGracefully(cleanExpireMsgExecutors, 5000, TimeUnit.MILLISECONDS); + } + + private void cleanExpireMsg() { + for (final Map.Entry next : rocketmqPullConsumer.getDefaultMQPullConsumerImpl() + .getRebalanceImpl().getProcessQueueTable().entrySet()) { + ProcessQueue pq = next.getValue(); + MessageQueue mq = next.getKey(); + ReadWriteLock lockTreeMap = getLockInProcessQueue(pq); + if (lockTreeMap == null) { + log.error("Gets tree map lock in process queue error, may be has compatibility issue"); + return; + } + + TreeMap msgTreeMap = pq.getMsgTreeMap(); + + int loop = msgTreeMap.size(); + for (int i = 0; i < loop; i++) { + MessageExt msg = null; + try { + lockTreeMap.readLock().lockInterruptibly(); + try { + if (!msgTreeMap.isEmpty()) { + msg = msgTreeMap.firstEntry().getValue(); + if (System.currentTimeMillis() - Long.parseLong(MessageAccessor.getConsumeStartTimeStamp(msg)) + > clientConfig.getRmqMessageConsumeTimeout() * 60 * 1000) { + //Expired, ack and remove it. + } else { + break; + } + } else { + break; + } + } finally { + lockTreeMap.readLock().unlock(); + } + } catch (InterruptedException e) { + log.error("Gets expired message exception", e); + } + + try { + rocketmqPullConsumer.sendMessageBack(msg, 3); + log.info("Send expired msg back. topic={}, msgId={}, storeHost={}, queueId={}, queueOffset={}", + msg.getTopic(), msg.getMsgId(), msg.getStoreHost(), msg.getQueueId(), msg.getQueueOffset()); + ack(mq, pq, msg); + } catch (Exception e) { + log.error("Send back expired msg exception", e); + } + } + } + } + + private ReadWriteLock getLockInProcessQueue(ProcessQueue pq) { + try { + return (ReadWriteLock) FieldUtils.readDeclaredField(pq, "lockTreeMap", true); + } catch (IllegalAccessException e) { + return null; + } + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/PullConsumerImpl.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/PullConsumerImpl.java new file mode 100644 index 0000000000..6491861f78 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/PullConsumerImpl.java @@ -0,0 +1,180 @@ +/* + * 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 connector.rocketmq.consumer; + +import connector.rocketmq.config.ClientConfig; +import connector.rocketmq.domain.ConsumeRequest; +import connector.rocketmq.utils.BeanUtils; +import connector.rocketmq.utils.OMSUtil; +import io.openmessaging.KeyValue; +import io.openmessaging.Message; +import io.openmessaging.OMSBuiltinKeys; +import io.openmessaging.consumer.PullConsumer; +import io.openmessaging.exception.OMSRuntimeException; +import org.apache.rocketmq.client.consumer.*; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.impl.consumer.ProcessQueue; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.remoting.protocol.LanguageCode; + +public class PullConsumerImpl implements PullConsumer { + private final DefaultMQPullConsumer rocketmqPullConsumer; + private final KeyValue properties; + private boolean started = false; + private final MQPullConsumerScheduleService pullConsumerScheduleService; + private final LocalMessageCache localMessageCache; + private final ClientConfig clientConfig; + + private final static InternalLogger log = ClientLogger.getLog(); + + public PullConsumerImpl(final KeyValue properties) { + this.properties = properties; + this.clientConfig = BeanUtils.populate(properties, ClientConfig.class); + + String consumerGroup = clientConfig.getConsumerId(); + if (null == consumerGroup || consumerGroup.isEmpty()) { + throw new OMSRuntimeException("-1", "Consumer Group is necessary for RocketMQ, please set it."); + } + pullConsumerScheduleService = new MQPullConsumerScheduleService(consumerGroup); + + this.rocketmqPullConsumer = pullConsumerScheduleService.getDefaultMQPullConsumer(); + + if ("true".equalsIgnoreCase(System.getenv("OMS_RMQ_DIRECT_NAME_SRV"))) { + String accessPoints = clientConfig.getAccessPoints(); + if (accessPoints == null || accessPoints.isEmpty()) { + throw new OMSRuntimeException("-1", "OMS AccessPoints is null or empty."); + } + this.rocketmqPullConsumer.setNamesrvAddr(accessPoints.replace(',', ';')); + } + + this.rocketmqPullConsumer.setConsumerGroup(consumerGroup); + + int maxReDeliveryTimes = clientConfig.getRmqMaxRedeliveryTimes(); + this.rocketmqPullConsumer.setMaxReconsumeTimes(maxReDeliveryTimes); + + String consumerId = OMSUtil.buildInstanceName(); + this.rocketmqPullConsumer.setInstanceName(consumerId); + properties.put(OMSBuiltinKeys.CONSUMER_ID, consumerId); + + this.rocketmqPullConsumer.setLanguage(LanguageCode.OMS); + + this.localMessageCache = new LocalMessageCache(this.rocketmqPullConsumer, clientConfig); + } + + @Override + public KeyValue attributes() { + return properties; + } + + @Override + public PullConsumer attachQueue(String queueName) { + registerPullTaskCallback(queueName); + return this; + } + + @Override + public PullConsumer attachQueue(String queueName, KeyValue attributes) { + registerPullTaskCallback(queueName); + return this; + } + + @Override + public PullConsumer detachQueue(String queueName) { + this.rocketmqPullConsumer.getRegisterTopics().remove(queueName); + return this; + } + + @Override + public Message receive() { + MessageExt rmqMsg = localMessageCache.poll(); + return rmqMsg == null ? null : OMSUtil.msgConvert(rmqMsg); + } + + @Override + public Message receive(final KeyValue properties) { + MessageExt rmqMsg = localMessageCache.poll(properties); + return rmqMsg == null ? null : OMSUtil.msgConvert(rmqMsg); + } + + @Override + public void ack(final String messageId) { + localMessageCache.ack(messageId); + } + + @Override + public void ack(final String messageId, final KeyValue properties) { + localMessageCache.ack(messageId); + } + + @Override + public synchronized void startup() { + if (!started) { + try { + this.pullConsumerScheduleService.start(); + this.localMessageCache.startup(); + } catch (MQClientException e) { + throw new OMSRuntimeException("-1", e); + } + } + this.started = true; + } + + private void registerPullTaskCallback(final String targetQueueName) { + this.pullConsumerScheduleService.registerPullTaskCallback(targetQueueName, new PullTaskCallback() { + @Override + public void doPullTask(final MessageQueue mq, final PullTaskContext context) { + MQPullConsumer consumer = context.getPullConsumer(); + try { + long offset = localMessageCache.nextPullOffset(mq); + + PullResult pullResult = consumer.pull(mq, "*", + offset, localMessageCache.nextPullBatchNums()); + ProcessQueue pq = rocketmqPullConsumer.getDefaultMQPullConsumerImpl().getRebalanceImpl() + .getProcessQueueTable().get(mq); + switch (pullResult.getPullStatus()) { + case FOUND: + if (pq != null) { + pq.putMessage(pullResult.getMsgFoundList()); + for (final MessageExt messageExt : pullResult.getMsgFoundList()) { + localMessageCache.submitConsumeRequest(new ConsumeRequest(messageExt, mq, pq)); + } + } + break; + default: + break; + } + localMessageCache.updatePullOffset(mq, pullResult.getNextBeginOffset()); + } catch (Exception e) { + log.error("An error occurred in pull message process.", e); + } + } + }); + } + + @Override + public synchronized void shutdown() { + if (this.started) { + this.localMessageCache.shutdown(); + this.pullConsumerScheduleService.shutdown(); + this.rocketmqPullConsumer.shutdown(); + } + this.started = false; + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/PushConsumerImpl.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/PushConsumerImpl.java new file mode 100644 index 0000000000..d876f56df4 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/PushConsumerImpl.java @@ -0,0 +1,211 @@ +/* + * 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 connector.rocketmq.consumer; + +import connector.rocketmq.config.ClientConfig; +import connector.rocketmq.domain.NonStandardKeys; +import connector.rocketmq.utils.BeanUtils; +import connector.rocketmq.utils.OMSUtil; +import io.openmessaging.BytesMessage; +import io.openmessaging.KeyValue; +import io.openmessaging.OMS; +import io.openmessaging.OMSBuiltinKeys; +import io.openmessaging.consumer.MessageListener; +import io.openmessaging.consumer.PushConsumer; +import io.openmessaging.exception.OMSRuntimeException; +import io.openmessaging.interceptor.ConsumerInterceptor; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.remoting.protocol.LanguageCode; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class PushConsumerImpl implements PushConsumer { + private final DefaultMQPushConsumer rocketmqPushConsumer; + private final KeyValue properties; + private boolean started = false; + private final Map subscribeTable = new ConcurrentHashMap<>(); + private final ClientConfig clientConfig; +// public final MessageListenerImpl messageListener = new MessageListenerImpl(); + + public PushConsumerImpl(final KeyValue properties) { + this.rocketmqPushConsumer = new DefaultMQPushConsumer(); + this.properties = properties; + this.clientConfig = BeanUtils.populate(properties, ClientConfig.class); + + if ("true".equalsIgnoreCase(System.getenv("OMS_RMQ_DIRECT_NAME_SRV"))) { + String accessPoints = clientConfig.getAccessPoints(); + if (accessPoints == null || accessPoints.isEmpty()) { + throw new OMSRuntimeException("-1", "OMS AccessPoints is null or empty."); + } + this.rocketmqPushConsumer.setNamesrvAddr(accessPoints.replace(',', ';')); + } + + String consumerGroup = clientConfig.getConsumerId(); + if (null == consumerGroup || consumerGroup.isEmpty()) { + throw new OMSRuntimeException("-1", "Consumer Group is necessary for RocketMQ, please set it."); + } + this.rocketmqPushConsumer.setConsumerGroup(consumerGroup); + this.rocketmqPushConsumer.setMaxReconsumeTimes(clientConfig.getRmqMaxRedeliveryTimes()); + this.rocketmqPushConsumer.setConsumeTimeout(clientConfig.getRmqMessageConsumeTimeout()); + this.rocketmqPushConsumer.setConsumeThreadMax(clientConfig.getRmqMaxConsumeThreadNums()); + this.rocketmqPushConsumer.setConsumeThreadMin(clientConfig.getRmqMinConsumeThreadNums()); + + String consumerId = OMSUtil.buildInstanceName(); + this.rocketmqPushConsumer.setInstanceName(consumerId); + properties.put(OMSBuiltinKeys.CONSUMER_ID, consumerId); + this.rocketmqPushConsumer.setLanguage(LanguageCode.OMS); + + this.rocketmqPushConsumer.registerMessageListener(new MessageListenerImpl()); + } + + @Override + public KeyValue attributes() { + return properties; + } + + @Override + public void resume() { + this.rocketmqPushConsumer.resume(); + } + + @Override + public void suspend() { + this.rocketmqPushConsumer.suspend(); + } + + @Override + public void suspend(long timeout) { + + } + + @Override + public boolean isSuspended() { + return this.rocketmqPushConsumer.getDefaultMQPushConsumerImpl().isPause(); + } + + @Override + public PushConsumer attachQueue(final String queueName, final MessageListener listener) { + this.subscribeTable.put(queueName, listener); + try { + this.rocketmqPushConsumer.subscribe(queueName, "*"); + } catch (MQClientException e) { + throw new OMSRuntimeException("-1", String.format("RocketMQ push consumer can't attach to %s.", queueName)); + } + return this; + } + + @Override + public PushConsumer attachQueue(String queueName, MessageListener listener, KeyValue attributes) { + return this.attachQueue(queueName, listener); + } + + @Override + public PushConsumer detachQueue(String queueName) { + this.subscribeTable.remove(queueName); + try { + this.rocketmqPushConsumer.unsubscribe(queueName); + } catch (Exception e) { + throw new OMSRuntimeException("-1", String.format("RocketMQ push consumer fails to unsubscribe topic: %s", queueName)); + } + return null; + } + + @Override + public void addInterceptor(ConsumerInterceptor interceptor) { + + } + + @Override + public void removeInterceptor(ConsumerInterceptor interceptor) { + + } + + @Override + public synchronized void startup() { + if (!started) { + try { + this.rocketmqPushConsumer.start(); + } catch (MQClientException e) { + throw new OMSRuntimeException("-1", e); + } + } + this.started = true; + } + + @Override + public synchronized void shutdown() { + if (this.started) { + this.rocketmqPushConsumer.shutdown(); + } + this.started = false; + } + + class MessageListenerImpl implements MessageListenerConcurrently { + + @Override + public ConsumeConcurrentlyStatus consumeMessage(List rmqMsgList, + ConsumeConcurrentlyContext contextRMQ) { + MessageExt rmqMsg = rmqMsgList.get(0); + BytesMessage omsMsg = OMSUtil.msgConvert(rmqMsg); + + MessageListener listener = PushConsumerImpl.this.subscribeTable.get(rmqMsg.getTopic()); + + if (listener == null) { + throw new OMSRuntimeException("-1", + String.format("The topic/queue %s isn't attached to this consumer", rmqMsg.getTopic())); + } + + final KeyValue contextProperties = OMS.newKeyValue(); + final CountDownLatch sync = new CountDownLatch(1); + + contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, ConsumeConcurrentlyStatus.RECONSUME_LATER.name()); + + MessageListener.Context context = new MessageListener.Context() { + @Override + public KeyValue attributes() { + return contextProperties; + } + + @Override + public void ack() { + sync.countDown(); + contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, + ConsumeConcurrentlyStatus.CONSUME_SUCCESS.name()); + } + }; + long begin = System.currentTimeMillis(); + listener.onReceived(omsMsg, context); + long costs = System.currentTimeMillis() - begin; + long timeoutMills = clientConfig.getRmqMessageConsumeTimeout() * 60 * 1000; + try { + sync.await(Math.max(0, timeoutMills - costs), TimeUnit.MILLISECONDS); + } catch (InterruptedException ignore) { + } + + return ConsumeConcurrentlyStatus.valueOf(contextProperties.getString(NonStandardKeys.MESSAGE_CONSUME_STATUS)); + } + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/RocketMQConsumerImpl.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/RocketMQConsumerImpl.java new file mode 100644 index 0000000000..2b73b672c5 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/consumer/RocketMQConsumerImpl.java @@ -0,0 +1,152 @@ +/* + * 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 connector.rocketmq.consumer; + +import com.webank.eventmesh.common.ThreadUtil; +import com.webank.runtime.configuration.CommonConfiguration; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.plugin.impl.MeshMQConsumer; +import com.webank.runtime.patch.ProxyConsumeConcurrentlyContext; +import connector.rocketmq.config.PropInitImpl; +import connector.rocketmq.utils.OMSUtil; +import io.openmessaging.KeyValue; +import io.openmessaging.Message; +import io.openmessaging.MessagingAccessPoint; +import io.openmessaging.OMS; +import io.openmessaging.consumer.MessageListener; +import io.openmessaging.consumer.PushConsumer; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageService; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.List; + +public class RocketMQConsumerImpl implements MeshMQConsumer { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public Logger messageLogger = LoggerFactory.getLogger("message"); + +// private DefaultMQPushConsumer defaultMQPushConsumer; + +// private PushConsumerImpl pushConsumer; + + private KeyValue properties = new PropInitImpl().initProp(); + String namesrv = ""; + private PushConsumer pushConsumer; + + @Override + public synchronized void init(boolean isBroadcast, CommonConfiguration commonConfiguration, + String consumerGroup) throws Exception { + // properties需要由runtime构建传入 +// pushConsumer = new PushConsumerImpl(properties); + MessagingAccessPoint messagingAccessPoint = OMS.getMessagingAccessPoint(namesrv, properties); + pushConsumer = messagingAccessPoint.createPushConsumer(properties); +// if (isBroadcast) { +// defaultMQPushConsumer = new DefaultMQPushConsumer(ProxyConstants.CONSUMER_GROUP_NAME_PREFIX + ProxyConstants.BROADCAST_PREFIX + consumerGroup); +// defaultMQPushConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); +// defaultMQPushConsumer.setMessageModel(MessageModel.BROADCASTING); +// } else { +// defaultMQPushConsumer = new DefaultMQPushConsumer(ProxyConstants.CONSUMER_GROUP_NAME_PREFIX + consumerGroup); +// defaultMQPushConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); +// defaultMQPushConsumer.setMessageModel(MessageModel.CLUSTERING); +// } +// +// defaultMQPushConsumer.setPollNameServerInterval(commonConfiguration.pollNameServerInteval); +// defaultMQPushConsumer.setHeartbeatBrokerInterval(commonConfiguration.heartbeatBrokerInterval); +// defaultMQPushConsumer.setPullThresholdForQueue(commonConfiguration.ackWindow); +// defaultMQPushConsumer.setNamesrvAddr(commonConfiguration.namesrvAddr); +// defaultMQPushConsumer.setPullBatchSize(commonConfiguration.pullBatchSize); +// defaultMQPushConsumer.setConsumeThreadMax(commonConfiguration.consumeThreadMax); +// defaultMQPushConsumer.setConsumeThreadMin(commonConfiguration.consumeThreadMin); +// defaultMQPushConsumer.setConsumeTimeout(commonConfiguration.consumeTimeout); + } + + @Override + public void setInstanceName(String instanceName) { +// defaultMQPushConsumer.setInstanceName(instanceName); + } + + @Override + public void registerMessageListener(MessageListenerConcurrently listener) { +// this.defaultMQPushConsumer.registerMessageListener(listener); + } + + @Override + public synchronized void start() throws Exception { +// ThreadUtil.randomSleep(50); +// +// if (this.defaultMQPushConsumer.getMessageListener() == null) { +// throw new Exception("no messageListener has been registered"); +// } + + pushConsumer.startup(); + +// defaultMQPushConsumer.unsubscribe(MixAll.getRetryTopic(defaultMQPushConsumer.getConsumerGroup())); + } + + @Override + public void subscribe(String topic) throws Exception { +// defaultMQPushConsumer.subscribe(topic, "*"); + pushConsumer.attachQueue(topic, new MessageListener() { + @Override + public void onReceived(Message message, Context context) { + context.ack(); + } + }); + } + + @Override + public void unsubscribe(String topic) throws Exception { +// defaultMQPushConsumer.unsubscribe(topic); + pushConsumer.detachQueue(topic); + } + + @Override + public boolean isPause() { + return pushConsumer.isSuspended(); + } + + @Override + public void pause() { +// defaultMQPushConsumer.getDefaultMQPushConsumerImpl().setPause(true); + pushConsumer.suspend(); + } + + @Override + public synchronized void shutdown() throws Exception { +// defaultMQPushConsumer.shutdown(); + pushConsumer.shutdown(); + } + + @Override + public void updateOffset(List msgs, ProxyConsumeConcurrentlyContext context) { +// ConsumeMessageService consumeMessageService = defaultMQPushConsumer.getDefaultMQPushConsumerImpl().getConsumeMessageService(); +// ((ConsumeMessageConcurrentlyService) consumeMessageService).updateOffset(msgs, context); + MessageListenerConcurrently pushConsumerMessageListener = (MessageListenerConcurrently) ((DefaultMQPushConsumer)pushConsumer).getMessageListener(); + pushConsumerMessageListener.consumeMessage(msgs, context); + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/BytesMessageImpl.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/BytesMessageImpl.java new file mode 100644 index 0000000000..14615d3014 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/BytesMessageImpl.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 connector.rocketmq.domain; + +import io.openmessaging.BytesMessage; +import io.openmessaging.KeyValue; +import io.openmessaging.Message; +import io.openmessaging.OMS; +import io.openmessaging.exception.OMSMessageFormatException; +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class BytesMessageImpl implements BytesMessage { + private KeyValue sysHeaders; + private KeyValue userHeaders; + private byte[] body; + + public BytesMessageImpl() { + this.sysHeaders = OMS.newKeyValue(); + this.userHeaders = OMS.newKeyValue(); + } + + @Override + public T getBody(Class type) throws OMSMessageFormatException { + if (type == byte[].class) { + return (T)body; + } + + throw new OMSMessageFormatException("", "Cannot assign byte[] to " + type.getName()); + } + + @Override + public BytesMessage setBody(final byte[] body) { + this.body = body; + return this; + } + + @Override + public KeyValue sysHeaders() { + return sysHeaders; + } + + @Override + public KeyValue userHeaders() { + return userHeaders; + } + + @Override + public Message putSysHeaders(String key, int value) { + sysHeaders.put(key, value); + return this; + } + + @Override + public Message putSysHeaders(String key, long value) { + sysHeaders.put(key, value); + return this; + } + + @Override + public Message putSysHeaders(String key, double value) { + sysHeaders.put(key, value); + return this; + } + + @Override + public Message putSysHeaders(String key, String value) { + sysHeaders.put(key, value); + return this; + } + + @Override + public Message putUserHeaders(String key, int value) { + userHeaders.put(key, value); + return this; + } + + @Override + public Message putUserHeaders(String key, long value) { + userHeaders.put(key, value); + return this; + } + + @Override + public Message putUserHeaders(String key, double value) { + userHeaders.put(key, value); + return this; + } + + @Override + public Message putUserHeaders(String key, String value) { + userHeaders.put(key, value); + return this; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/ConsumeRequest.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/ConsumeRequest.java new file mode 100644 index 0000000000..02b7a949d6 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/ConsumeRequest.java @@ -0,0 +1,55 @@ +/* + * 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 connector.rocketmq.domain; + +import org.apache.rocketmq.client.impl.consumer.ProcessQueue; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; + +public class ConsumeRequest { + private final MessageExt messageExt; + private final MessageQueue messageQueue; + private final ProcessQueue processQueue; + private long startConsumeTimeMillis; + + public ConsumeRequest(final MessageExt messageExt, final MessageQueue messageQueue, + final ProcessQueue processQueue) { + this.messageExt = messageExt; + this.messageQueue = messageQueue; + this.processQueue = processQueue; + } + + public MessageExt getMessageExt() { + return messageExt; + } + + public MessageQueue getMessageQueue() { + return messageQueue; + } + + public ProcessQueue getProcessQueue() { + return processQueue; + } + + public long getStartConsumeTimeMillis() { + return startConsumeTimeMillis; + } + + public void setStartConsumeTimeMillis(final long startConsumeTimeMillis) { + this.startConsumeTimeMillis = startConsumeTimeMillis; + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/NonStandardKeys.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/NonStandardKeys.java new file mode 100644 index 0000000000..ad3207a908 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/NonStandardKeys.java @@ -0,0 +1,30 @@ +/* + * 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 connector.rocketmq.domain; + +public interface NonStandardKeys { + String CONSUMER_GROUP = "rmq.consumer.group"; + String PRODUCER_GROUP = "rmq.producer.group"; + String MAX_REDELIVERY_TIMES = "rmq.max.redelivery.times"; + String MESSAGE_CONSUME_TIMEOUT = "rmq.message.consume.timeout"; + String MAX_CONSUME_THREAD_NUMS = "rmq.max.consume.thread.nums"; + String MIN_CONSUME_THREAD_NUMS = "rmq.min.consume.thread.nums"; + String MESSAGE_CONSUME_STATUS = "rmq.message.consume.status"; + String MESSAGE_DESTINATION = "rmq.message.destination"; + String PULL_MESSAGE_BATCH_NUMS = "rmq.pull.message.batch.nums"; + String PULL_MESSAGE_CACHE_CAPACITY = "rmq.pull.message.cache.capacity"; +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/conf/EventMeshTCPClientConfig.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/RocketMQConstants.java similarity index 73% rename from eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/conf/EventMeshTCPClientConfig.java rename to eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/RocketMQConstants.java index 4ef990d1dd..31fd2949c9 100644 --- a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/conf/EventMeshTCPClientConfig.java +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/RocketMQConstants.java @@ -14,19 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package connector.rocketmq.domain; -package org.apache.eventmesh.client.tcp.conf; +public interface RocketMQConstants { -import org.apache.eventmesh.common.protocol.tcp.UserAgent; + /** + * Key of scheduled message delivery time + */ + String START_DELIVER_TIME = "__STARTDELIVERTIME"; -import lombok.Builder; -import lombok.Data; - -@Data -@Builder -public class EventMeshTCPClientConfig { - - private String host; - private int port; - private UserAgent userAgent; } diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/SendResultImpl.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/SendResultImpl.java new file mode 100644 index 0000000000..4501175dcd --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/domain/SendResultImpl.java @@ -0,0 +1,39 @@ +/* + * 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 connector.rocketmq.domain; + +import io.openmessaging.KeyValue; +import io.openmessaging.producer.SendResult; + +public class SendResultImpl implements SendResult { + private String messageId; + private KeyValue properties; + + public SendResultImpl(final String messageId, final KeyValue properties) { + this.messageId = messageId; + this.properties = properties; + } + + @Override + public String messageId() { + return messageId; + } + + public KeyValue properties() { + return properties; + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/producer/AbstractOMSProducer.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/producer/AbstractOMSProducer.java new file mode 100644 index 0000000000..31c6d092f4 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/producer/AbstractOMSProducer.java @@ -0,0 +1,140 @@ +/* + * 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 connector.rocketmq.producer; + +import connector.rocketmq.config.ClientConfig; +import connector.rocketmq.domain.BytesMessageImpl; +import connector.rocketmq.utils.BeanUtils; +import io.openmessaging.*; +import io.openmessaging.exception.OMSMessageFormatException; +import io.openmessaging.exception.OMSNotSupportedException; +import io.openmessaging.exception.OMSRuntimeException; +import io.openmessaging.exception.OMSTimeOutException; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.remoting.exception.RemotingConnectException; +import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; +import org.apache.rocketmq.remoting.protocol.LanguageCode; + +import static connector.rocketmq.utils.OMSUtil.buildInstanceName; + +public abstract class AbstractOMSProducer implements ServiceLifecycle, MessageFactory { + final static InternalLogger log = ClientLogger.getLog(); + final KeyValue properties; + final DefaultMQProducer rocketmqProducer; + private boolean started = false; + private final ClientConfig clientConfig; + + AbstractOMSProducer(final KeyValue properties) { + this.properties = properties; + this.rocketmqProducer = new DefaultMQProducer(); + this.clientConfig = BeanUtils.populate(properties, ClientConfig.class); + + if ("true".equalsIgnoreCase(System.getenv("OMS_RMQ_DIRECT_NAME_SRV"))) { + String accessPoints = clientConfig.getAccessPoints(); + if (accessPoints == null || accessPoints.isEmpty()) { + throw new OMSRuntimeException("-1", "OMS AccessPoints is null or empty."); + } + + this.rocketmqProducer.setNamesrvAddr(accessPoints.replace(',', ';')); + } + + this.rocketmqProducer.setProducerGroup(clientConfig.getRmqProducerGroup()); + + String producerId = buildInstanceName(); + this.rocketmqProducer.setSendMsgTimeout(clientConfig.getOperationTimeout()); + this.rocketmqProducer.setInstanceName(producerId); + this.rocketmqProducer.setMaxMessageSize(1024 * 1024 * 4); + this.rocketmqProducer.setLanguage(LanguageCode.OMS); + properties.put(OMSBuiltinKeys.PRODUCER_ID, producerId); + } + + @Override + public synchronized void startup() { + if (!started) { + try { + this.rocketmqProducer.start(); + } catch (MQClientException e) { + throw new OMSRuntimeException("-1", e); + } + } + this.started = true; + } + + @Override + public synchronized void shutdown() { + if (this.started) { + this.rocketmqProducer.shutdown(); + } + this.started = false; + } + + OMSRuntimeException checkProducerException(String topic, String msgId, Throwable e) { + if (e instanceof MQClientException) { + if (e.getCause() != null) { + if (e.getCause() instanceof RemotingTimeoutException) { + return new OMSTimeOutException("-1", String.format("Send message to broker timeout, %dms, Topic=%s, msgId=%s", + this.rocketmqProducer.getSendMsgTimeout(), topic, msgId), e); + } else if (e.getCause() instanceof MQBrokerException || e.getCause() instanceof RemotingConnectException) { + if (e.getCause() instanceof MQBrokerException) { + MQBrokerException brokerException = (MQBrokerException) e.getCause(); + return new OMSRuntimeException("-1", String.format("Received a broker exception, Topic=%s, msgId=%s, %s", + topic, msgId, brokerException.getErrorMessage()), e); + } + + if (e.getCause() instanceof RemotingConnectException) { + RemotingConnectException connectException = (RemotingConnectException)e.getCause(); + return new OMSRuntimeException("-1", + String.format("Network connection experiences failures. Topic=%s, msgId=%s, %s", + topic, msgId, connectException.getMessage()), + e); + } + } + } + // Exception thrown by local. + else { + MQClientException clientException = (MQClientException) e; + if (-1 == clientException.getResponseCode()) { + return new OMSRuntimeException("-1", String.format("Topic does not exist, Topic=%s, msgId=%s", + topic, msgId), e); + } else if (ResponseCode.MESSAGE_ILLEGAL == clientException.getResponseCode()) { + return new OMSMessageFormatException("-1", String.format("A illegal message for RocketMQ, Topic=%s, msgId=%s", + topic, msgId), e); + } + } + } + return new OMSRuntimeException("-1", "Send message to RocketMQ broker failed.", e); + } + + protected void checkMessageType(Message message) { + if (!(message instanceof BytesMessage)) { + throw new OMSNotSupportedException("-1", "Only BytesMessage is supported."); + } + } + + @Override + public BytesMessage createBytesMessage(String queue, byte[] body) { + BytesMessage message = new BytesMessageImpl(); + message.setBody(body); + message.sysHeaders().put(Message.BuiltinKeys.DESTINATION, queue); + return message; + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/producer/ProducerImpl.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/producer/ProducerImpl.java new file mode 100644 index 0000000000..c300f73877 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/producer/ProducerImpl.java @@ -0,0 +1,146 @@ +/* + * 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 connector.rocketmq.producer; + +import connector.rocketmq.promise.DefaultPromise; +import connector.rocketmq.utils.OMSUtil; +import io.openmessaging.BytesMessage; +import io.openmessaging.KeyValue; +import io.openmessaging.Message; +import io.openmessaging.Promise; +import io.openmessaging.exception.OMSRuntimeException; +import io.openmessaging.interceptor.ProducerInterceptor; +import io.openmessaging.producer.BatchMessageSender; +import io.openmessaging.producer.LocalTransactionExecutor; +import io.openmessaging.producer.Producer; +import io.openmessaging.producer.SendResult; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendStatus; + +import static connector.rocketmq.utils.OMSUtil.msgConvert; + + +public class ProducerImpl extends AbstractOMSProducer implements Producer { + + public ProducerImpl(final KeyValue properties) { + super(properties); + } + + @Override + public KeyValue attributes() { + return properties; + } + + @Override + public SendResult send(final Message message) { + return send(message, this.rocketmqProducer.getSendMsgTimeout()); + } + + @Override + public SendResult send(final Message message, final KeyValue properties) { + long timeout = properties.containsKey(Message.BuiltinKeys.TIMEOUT) + ? properties.getInt(Message.BuiltinKeys.TIMEOUT) : this.rocketmqProducer.getSendMsgTimeout(); + return send(message, timeout); + } + + @Override + public SendResult send(Message message, LocalTransactionExecutor branchExecutor, KeyValue attributes) { + return null; + } + + private SendResult send(final Message message, long timeout) { + checkMessageType(message); + org.apache.rocketmq.common.message.Message rmqMessage = msgConvert((BytesMessage) message); + try { + org.apache.rocketmq.client.producer.SendResult rmqResult = this.rocketmqProducer.send(rmqMessage, timeout); + if (!rmqResult.getSendStatus().equals(SendStatus.SEND_OK)) { + log.error(String.format("Send message to RocketMQ failed, %s", message)); + throw new OMSRuntimeException("-1", "Send message to RocketMQ broker failed."); + } + message.sysHeaders().put(Message.BuiltinKeys.MESSAGE_ID, rmqResult.getMsgId()); + return OMSUtil.sendResultConvert(rmqResult); + } catch (Exception e) { + log.error(String.format("Send message to RocketMQ failed, %s", message), e); + throw checkProducerException(rmqMessage.getTopic(), message.sysHeaders().getString(Message.BuiltinKeys.MESSAGE_ID), e); + } + } + + @Override + public Promise sendAsync(final Message message) { + return sendAsync(message, this.rocketmqProducer.getSendMsgTimeout()); + } + + @Override + public Promise sendAsync(final Message message, final KeyValue properties) { + long timeout = properties.containsKey(Message.BuiltinKeys.TIMEOUT) + ? properties.getInt(Message.BuiltinKeys.TIMEOUT) : this.rocketmqProducer.getSendMsgTimeout(); + return sendAsync(message, timeout); + } + + private Promise sendAsync(final Message message, long timeout) { + checkMessageType(message); + org.apache.rocketmq.common.message.Message rmqMessage = msgConvert((BytesMessage) message); + final Promise promise = new DefaultPromise<>(); + try { + this.rocketmqProducer.send(rmqMessage, new SendCallback() { + @Override + public void onSuccess(final org.apache.rocketmq.client.producer.SendResult rmqResult) { + message.sysHeaders().put(Message.BuiltinKeys.MESSAGE_ID, rmqResult.getMsgId()); + promise.set(OMSUtil.sendResultConvert(rmqResult)); + } + + @Override + public void onException(final Throwable e) { + promise.setFailure(e); + } + }, timeout); + } catch (Exception e) { + promise.setFailure(e); + } + return promise; + } + + @Override + public void sendOneway(final Message message) { + checkMessageType(message); + org.apache.rocketmq.common.message.Message rmqMessage = msgConvert((BytesMessage) message); + try { + this.rocketmqProducer.sendOneway(rmqMessage); + } catch (Exception ignore) { //Ignore the oneway exception. + } + } + + @Override + public void sendOneway(final Message message, final KeyValue properties) { + sendOneway(message); + } + + @Override + public BatchMessageSender createBatchMessageSender() { + return null; + } + + @Override + public void addInterceptor(ProducerInterceptor interceptor) { + + } + + @Override + public void removeInterceptor(ProducerInterceptor interceptor) { + + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/promise/DefaultPromise.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/promise/DefaultPromise.java new file mode 100644 index 0000000000..dd6958a7d3 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/promise/DefaultPromise.java @@ -0,0 +1,225 @@ +/* + * 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 connector.rocketmq.promise; + +import io.openmessaging.FutureListener; +import io.openmessaging.Promise; +import io.openmessaging.exception.OMSRuntimeException; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class DefaultPromise implements Promise { + private static final InternalLogger LOG = InternalLoggerFactory.getLogger(DefaultPromise.class); + private final Object lock = new Object(); + private volatile FutureState state = FutureState.DOING; + private V result = null; + private long timeout; + private long createTime; + private Throwable exception = null; + private List> promiseListenerList; + + public DefaultPromise() { + createTime = System.currentTimeMillis(); + promiseListenerList = new ArrayList<>(); + timeout = 5000; + } + + @Override + public boolean cancel(final boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return state.isCancelledState(); + } + + @Override + public boolean isDone() { + return state.isDoneState(); + } + + @Override + public V get() { + return result; + } + + @Override + public V get(final long timeout) { + synchronized (lock) { + if (!isDoing()) { + return getValueOrThrowable(); + } + + if (timeout <= 0) { + try { + lock.wait(); + } catch (Exception e) { + cancel(e); + } + return getValueOrThrowable(); + } else { + long waitTime = timeout - (System.currentTimeMillis() - createTime); + if (waitTime > 0) { + for (; ; ) { + try { + lock.wait(waitTime); + } catch (InterruptedException e) { + LOG.error("promise get value interrupted,excepiton:{}", e.getMessage()); + } + + if (!isDoing()) { + break; + } else { + waitTime = timeout - (System.currentTimeMillis() - createTime); + if (waitTime <= 0) { + break; + } + } + } + } + + if (isDoing()) { + timeoutSoCancel(); + } + } + return getValueOrThrowable(); + } + } + + @Override + public boolean set(final V value) { + if (value == null) + return false; + this.result = value; + return done(); + } + + @Override + public boolean setFailure(final Throwable cause) { + if (cause == null) + return false; + this.exception = cause; + return done(); + } + + @Override + public void addListener(final FutureListener listener) { + if (listener == null) { + throw new NullPointerException("FutureListener is null"); + } + + boolean notifyNow = false; + synchronized (lock) { + if (!isDoing()) { + notifyNow = true; + } else { + if (promiseListenerList == null) { + promiseListenerList = new ArrayList<>(); + } + promiseListenerList.add(listener); + } + } + + if (notifyNow) { + notifyListener(listener); + } + } + + @Override + public Throwable getThrowable() { + return exception; + } + + private void notifyListeners() { + if (promiseListenerList != null) { + for (FutureListener listener : promiseListenerList) { + notifyListener(listener); + } + } + } + + private boolean isSuccess() { + return isDone() && (exception == null); + } + + private void timeoutSoCancel() { + synchronized (lock) { + if (!isDoing()) { + return; + } + state = FutureState.CANCELLED; + exception = new RuntimeException("Get request result is timeout or interrupted"); + lock.notifyAll(); + } + notifyListeners(); + } + + private V getValueOrThrowable() { + if (exception != null) { + Throwable e = exception.getCause() != null ? exception.getCause() : exception; + throw new OMSRuntimeException("-1", e); + } + notifyListeners(); + return result; + } + + private boolean isDoing() { + return state.isDoingState(); + } + + private boolean done() { + synchronized (lock) { + if (!isDoing()) { + return false; + } + + state = FutureState.DONE; + lock.notifyAll(); + } + + notifyListeners(); + return true; + } + + private void notifyListener(final FutureListener listener) { + try { + listener.operationComplete(this); + } catch (Throwable t) { + LOG.error("notifyListener {} Error:{}", listener.getClass().getSimpleName(), t); + } + } + + private boolean cancel(Exception e) { + synchronized (lock) { + if (!isDoing()) { + return false; + } + + state = FutureState.CANCELLED; + exception = e; + lock.notifyAll(); + } + + notifyListeners(); + return true; + } +} + diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/promise/FutureState.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/promise/FutureState.java new file mode 100644 index 0000000000..6132bd0173 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/promise/FutureState.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package connector.rocketmq.promise; + +public enum FutureState { + /** + * the task is doing + **/ + DOING(0), + /** + * the task is done + **/ + DONE(1), + /** + * ths task is cancelled + **/ + CANCELLED(2); + + public final int value; + + private FutureState(int value) { + this.value = value; + } + + public boolean isCancelledState() { + return this == CANCELLED; + } + + public boolean isDoneState() { + return this == DONE; + } + + public boolean isDoingState() { + return this == DOING; + } +} diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/utils/BeanUtils.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/utils/BeanUtils.java new file mode 100644 index 0000000000..6a6418c0d8 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/utils/BeanUtils.java @@ -0,0 +1,187 @@ +/* + * 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 connector.rocketmq.utils; + +import io.openmessaging.KeyValue; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.logging.InternalLogger; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +public final class BeanUtils { + final static InternalLogger log = ClientLogger.getLog(); + + /** + * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}. + */ + private static Map, Class> primitiveWrapperMap = new HashMap, Class>(); + + static { + primitiveWrapperMap.put(Boolean.TYPE, Boolean.class); + primitiveWrapperMap.put(Byte.TYPE, Byte.class); + primitiveWrapperMap.put(Character.TYPE, Character.class); + primitiveWrapperMap.put(Short.TYPE, Short.class); + primitiveWrapperMap.put(Integer.TYPE, Integer.class); + primitiveWrapperMap.put(Long.TYPE, Long.class); + primitiveWrapperMap.put(Double.TYPE, Double.class); + primitiveWrapperMap.put(Float.TYPE, Float.class); + primitiveWrapperMap.put(Void.TYPE, Void.TYPE); + } + + private static Map, Class> wrapperMap = new HashMap, Class>(); + + static { + for (final Class primitiveClass : primitiveWrapperMap.keySet()) { + final Class wrapperClass = primitiveWrapperMap.get(primitiveClass); + if (!primitiveClass.equals(wrapperClass)) { + wrapperMap.put(wrapperClass, primitiveClass); + } + } + wrapperMap.put(String.class, String.class); + } + + /** + *

Populate the JavaBeans properties of the specified bean, based on + * the specified name/value pairs. This method uses Java reflection APIs + * to identify corresponding "property setter" method names, and deals + * with setter arguments of type String, boolean, + * int, long, float, and + * double.

+ * + *

The particular setter method to be called for each property is + * determined using the usual JavaBeans introspection mechanisms. Thus, + * you may identify custom setter methods using a BeanInfo class that is + * associated with the class of the bean itself. If no such BeanInfo + * class is available, the standard method name conversion ("set" plus + * the capitalized name of the property in question) is used.

+ * + *

NOTE: It is contrary to the JavaBeans Specification + * to have more than one setter method (with different argument + * signatures) for the same property.

+ * + * @param clazz JavaBean class whose properties are being populated + * @param properties Map keyed by property name, with the corresponding (String or String[]) value(s) to be set + * @param Class type + * @return Class instance + */ + public static T populate(final Properties properties, final Class clazz) { + T obj = null; + try { + obj = clazz.newInstance(); + return populate(properties, obj); + } catch (Throwable e) { + log.warn("Error occurs !", e); + } + return obj; + } + + public static T populate(final KeyValue properties, final Class clazz) { + T obj = null; + try { + obj = clazz.newInstance(); + return populate(properties, obj); + } catch (Throwable e) { + log.warn("Error occurs !", e); + } + return obj; + } + + public static Class getMethodClass(Class clazz, String methodName) { + Method[] methods = clazz.getMethods(); + for (Method method : methods) { + if (method.getName().equalsIgnoreCase(methodName)) { + return method.getParameterTypes()[0]; + } + } + return null; + } + + public static void setProperties(Class clazz, Object obj, String methodName, + Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class parameterClass = getMethodClass(clazz, methodName); + Method setterMethod = clazz.getMethod(methodName, parameterClass); + if (parameterClass == Boolean.TYPE) { + setterMethod.invoke(obj, Boolean.valueOf(value.toString())); + } else if (parameterClass == Integer.TYPE) { + setterMethod.invoke(obj, Integer.valueOf(value.toString())); + } else if (parameterClass == Double.TYPE) { + setterMethod.invoke(obj, Double.valueOf(value.toString())); + } else if (parameterClass == Float.TYPE) { + setterMethod.invoke(obj, Float.valueOf(value.toString())); + } else if (parameterClass == Long.TYPE) { + setterMethod.invoke(obj, Long.valueOf(value.toString())); + } else { + setterMethod.invoke(obj, value); + } + } + + public static T populate(final Properties properties, final T obj) { + Class clazz = obj.getClass(); + try { + + Set> entries = properties.entrySet(); + for (Map.Entry entry : entries) { + String entryKey = entry.getKey().toString(); + String[] keyGroup = entryKey.split("\\."); + for (int i = 0; i < keyGroup.length; i++) { + keyGroup[i] = keyGroup[i].toLowerCase(); + keyGroup[i] = StringUtils.capitalize(keyGroup[i]); + } + String beanFieldNameWithCapitalization = StringUtils.join(keyGroup); + try { + setProperties(clazz, obj, "set" + beanFieldNameWithCapitalization, entry.getValue()); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { + //ignored... + } + } + } catch (RuntimeException e) { + log.warn("Error occurs !", e); + } + return obj; + } + + public static T populate(final KeyValue properties, final T obj) { + Class clazz = obj.getClass(); + try { + + final Set keySet = properties.keySet(); + for (String key : keySet) { + String[] keyGroup = key.split("[\\._]"); + for (int i = 0; i < keyGroup.length; i++) { + keyGroup[i] = keyGroup[i].toLowerCase(); + keyGroup[i] = StringUtils.capitalize(keyGroup[i]); + } + String beanFieldNameWithCapitalization = StringUtils.join(keyGroup); + try { + setProperties(clazz, obj, "set" + beanFieldNameWithCapitalization, properties.getString(key)); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { + //ignored... + } + } + } catch (RuntimeException e) { + log.warn("Error occurs !", e); + } + return obj; + } +} + diff --git a/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/utils/OMSUtil.java b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/utils/OMSUtil.java new file mode 100644 index 0000000000..0656c918ea --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/java/connector/rocketmq/utils/OMSUtil.java @@ -0,0 +1,181 @@ +/* + * 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 connector.rocketmq.utils; + +import connector.rocketmq.domain.BytesMessageImpl; +import connector.rocketmq.domain.RocketMQConstants; +import connector.rocketmq.domain.SendResultImpl; +import io.openmessaging.BytesMessage; +import io.openmessaging.KeyValue; +import io.openmessaging.Message.BuiltinKeys; +import io.openmessaging.OMS; +import io.openmessaging.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.UtilAll; +import org.apache.rocketmq.common.message.MessageAccessor; + +import java.lang.reflect.Field; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +public class OMSUtil { + + /** + * Builds a OMS client instance name. + * + * @return a unique instance name + */ + public static String buildInstanceName() { + return Integer.toString(UtilAll.getPid()) + "%OpenMessaging" + "%" + System.nanoTime(); + } + + public static org.apache.rocketmq.common.message.Message msgConvert(BytesMessage omsMessage) { + org.apache.rocketmq.common.message.Message rmqMessage = new org.apache.rocketmq.common.message.Message(); + rmqMessage.setBody(omsMessage.getBody(byte[].class)); + + KeyValue sysHeaders = omsMessage.sysHeaders(); + KeyValue userHeaders = omsMessage.userHeaders(); + + //All destinations in RocketMQ use Topic + rmqMessage.setTopic(sysHeaders.getString(BuiltinKeys.DESTINATION)); + + if (sysHeaders.containsKey(BuiltinKeys.START_TIME)) { + long deliverTime = sysHeaders.getLong(BuiltinKeys.START_TIME, 0); + if (deliverTime > 0) { + rmqMessage.putUserProperty(RocketMQConstants.START_DELIVER_TIME, String.valueOf(deliverTime)); + } + } + + for (String key : userHeaders.keySet()) { + MessageAccessor.putProperty(rmqMessage, key, userHeaders.getString(key)); + } + + //System headers has a high priority + for (String key : sysHeaders.keySet()) { + MessageAccessor.putProperty(rmqMessage, key, sysHeaders.getString(key)); + } + + return rmqMessage; + } + + public static BytesMessage msgConvert(org.apache.rocketmq.common.message.MessageExt rmqMsg) { + BytesMessage omsMsg = new BytesMessageImpl(); + omsMsg.setBody(rmqMsg.getBody()); + + KeyValue headers = omsMsg.sysHeaders(); + KeyValue properties = omsMsg.userHeaders(); + + final Set> entries = rmqMsg.getProperties().entrySet(); + + for (final Map.Entry entry : entries) { + if (isOMSHeader(entry.getKey())) { + headers.put(entry.getKey(), entry.getValue()); + } else { + properties.put(entry.getKey(), entry.getValue()); + } + } + + omsMsg.putSysHeaders(BuiltinKeys.MESSAGE_ID, rmqMsg.getMsgId()); + + omsMsg.putSysHeaders(BuiltinKeys.DESTINATION, rmqMsg.getTopic()); + + omsMsg.putSysHeaders(BuiltinKeys.SEARCH_KEYS, rmqMsg.getKeys()); + omsMsg.putSysHeaders(BuiltinKeys.BORN_HOST, String.valueOf(rmqMsg.getBornHost())); + omsMsg.putSysHeaders(BuiltinKeys.BORN_TIMESTAMP, rmqMsg.getBornTimestamp()); + omsMsg.putSysHeaders(BuiltinKeys.STORE_HOST, String.valueOf(rmqMsg.getStoreHost())); + omsMsg.putSysHeaders(BuiltinKeys.STORE_TIMESTAMP, rmqMsg.getStoreTimestamp()); + return omsMsg; + } + + public static boolean isOMSHeader(String value) { + for (Field field : BuiltinKeys.class.getDeclaredFields()) { + try { + if (field.get(BuiltinKeys.class).equals(value)) { + return true; + } + } catch (IllegalAccessException e) { + return false; + } + } + return false; + } + + /** + * Convert a RocketMQ SEND_OK SendResult instance to a OMS SendResult. + */ + public static SendResult sendResultConvert(org.apache.rocketmq.client.producer.SendResult rmqResult) { + assert rmqResult.getSendStatus().equals(SendStatus.SEND_OK); + return new SendResultImpl(rmqResult.getMsgId(), OMS.newKeyValue()); + } + + public static KeyValue buildKeyValue(KeyValue... keyValues) { + KeyValue keyValue = OMS.newKeyValue(); + for (KeyValue properties : keyValues) { + for (String key : properties.keySet()) { + keyValue.put(key, properties.getString(key)); + } + } + return keyValue; + } + + /** + * Returns an iterator that cycles indefinitely over the elements of {@code Iterable}. + */ + public static Iterator cycle(final Iterable iterable) { + return new Iterator() { + Iterator iterator = new Iterator() { + @Override + public synchronized boolean hasNext() { + return false; + } + + @Override + public synchronized T next() { + throw new NoSuchElementException(); + } + + @Override + public synchronized void remove() { + //Ignore + } + }; + + @Override + public synchronized boolean hasNext() { + return iterator.hasNext() || iterable.iterator().hasNext(); + } + + @Override + public synchronized T next() { + if (!iterator.hasNext()) { + iterator = iterable.iterator(); + if (!iterator.hasNext()) { + throw new NoSuchElementException(); + } + } + return iterator.next(); + } + + @Override + public synchronized void remove() { + iterator.remove(); + } + }; + } +} diff --git a/eventmesh-connector-rocketmq/src/main/resources/META-INF/services/com.webank.runtime.configuration.PropInit b/eventmesh-connector-rocketmq/src/main/resources/META-INF/services/com.webank.runtime.configuration.PropInit new file mode 100644 index 0000000000..12265fd7a2 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/main/resources/META-INF/services/com.webank.runtime.configuration.PropInit @@ -0,0 +1 @@ +connector.rocketmq.config.PropInitImpl \ No newline at end of file diff --git a/eventmesh-connector-rocketmq/src/test/java/rocketmq/consumer/LocalMessageCacheTest.java b/eventmesh-connector-rocketmq/src/test/java/rocketmq/consumer/LocalMessageCacheTest.java new file mode 100644 index 0000000000..93faaacd6f --- /dev/null +++ b/eventmesh-connector-rocketmq/src/test/java/rocketmq/consumer/LocalMessageCacheTest.java @@ -0,0 +1,90 @@ +/* + * 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 rocketmq.consumer; + +import connector.rocketmq.config.ClientConfig; +import connector.rocketmq.consumer.LocalMessageCache; +import connector.rocketmq.domain.ConsumeRequest; +import connector.rocketmq.domain.NonStandardKeys; +import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import static org.assertj.core.api.Assertions.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class LocalMessageCacheTest { + private LocalMessageCache localMessageCache; + @Mock + private DefaultMQPullConsumer rocketmqPullConsume; + @Mock + private ConsumeRequest consumeRequest; + + @Before + public void init() { + ClientConfig clientConfig = new ClientConfig(); + clientConfig.setRmqPullMessageBatchNums(512); + clientConfig.setRmqPullMessageCacheCapacity(1024); + localMessageCache = new LocalMessageCache(rocketmqPullConsume, clientConfig); + } + + @Test + public void testNextPullBatchNums() throws Exception { + assertThat(localMessageCache.nextPullBatchNums()).isEqualTo(512); + for (int i = 0; i < 513; i++) { + localMessageCache.submitConsumeRequest(consumeRequest); + } + assertThat(localMessageCache.nextPullBatchNums()).isEqualTo(511); + } + + @Test + public void testNextPullOffset() throws Exception { + MessageQueue messageQueue = new MessageQueue(); + when(rocketmqPullConsume.fetchConsumeOffset(any(MessageQueue.class), anyBoolean())) + .thenReturn(123L); + assertThat(localMessageCache.nextPullOffset(new MessageQueue())).isEqualTo(123L); + } + + @Test + public void testUpdatePullOffset() throws Exception { + MessageQueue messageQueue = new MessageQueue(); + localMessageCache.updatePullOffset(messageQueue, 124L); + assertThat(localMessageCache.nextPullOffset(messageQueue)).isEqualTo(124L); + } + + @Test + public void testSubmitConsumeRequest() throws Exception { + byte[] body = new byte[] {'1', '2', '3'}; + MessageExt consumedMsg = new MessageExt(); + consumedMsg.setMsgId("NewMsgId"); + consumedMsg.setBody(body); + consumedMsg.putUserProperty(NonStandardKeys.MESSAGE_DESTINATION, "TOPIC"); + consumedMsg.setTopic("HELLO_QUEUE"); + + when(consumeRequest.getMessageExt()).thenReturn(consumedMsg); + localMessageCache.submitConsumeRequest(consumeRequest); + assertThat(localMessageCache.poll()).isEqualTo(consumedMsg); + } +} \ No newline at end of file diff --git a/eventmesh-connector-rocketmq/src/test/java/rocketmq/consumer/PullConsumerImplTest.java b/eventmesh-connector-rocketmq/src/test/java/rocketmq/consumer/PullConsumerImplTest.java new file mode 100644 index 0000000000..6effe95f89 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/test/java/rocketmq/consumer/PullConsumerImplTest.java @@ -0,0 +1,97 @@ +/* + * 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 rocketmq.consumer; + +import connector.rocketmq.config.ClientConfig; +import connector.rocketmq.consumer.LocalMessageCache; +import connector.rocketmq.consumer.PullConsumerImpl; +import connector.rocketmq.domain.NonStandardKeys; +import io.openmessaging.*; +import io.openmessaging.consumer.PullConsumer; +import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; +import org.apache.rocketmq.common.message.MessageExt; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.lang.reflect.Field; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class PullConsumerImplTest { + private PullConsumer consumer; + private String queueName = "HELLO_QUEUE"; + + @Mock + private DefaultMQPullConsumer rocketmqPullConsumer; + private LocalMessageCache localMessageCache = null; + + @Before + public void init() throws NoSuchFieldException, IllegalAccessException { + final MessagingAccessPoint messagingAccessPoint = OMS + .getMessagingAccessPoint("oms:rocketmq://IP1:9876,IP2:9876/namespace"); + + consumer = messagingAccessPoint.createPullConsumer(OMS.newKeyValue().put(OMSBuiltinKeys.CONSUMER_ID, "TestGroup")); + consumer.attachQueue(queueName); + + Field field = PullConsumerImpl.class.getDeclaredField("rocketmqPullConsumer"); + field.setAccessible(true); + field.set(consumer, rocketmqPullConsumer); //Replace + + ClientConfig clientConfig = new ClientConfig(); + clientConfig.setOperationTimeout(200); + localMessageCache = spy(new LocalMessageCache(rocketmqPullConsumer, clientConfig)); + + field = PullConsumerImpl.class.getDeclaredField("localMessageCache"); + field.setAccessible(true); + field.set(consumer, localMessageCache); + + messagingAccessPoint.startup(); + consumer.startup(); + } + + @Test + public void testPoll() { + final byte[] testBody = new byte[] {'a', 'b'}; + MessageExt consumedMsg = new MessageExt(); + consumedMsg.setMsgId("NewMsgId"); + consumedMsg.setBody(testBody); + consumedMsg.putUserProperty(NonStandardKeys.MESSAGE_DESTINATION, "TOPIC"); + consumedMsg.setTopic(queueName); + + when(localMessageCache.poll()).thenReturn(consumedMsg); + + Message message = consumer.receive(); + assertThat(message.sysHeaders().getString(Message.BuiltinKeys.MESSAGE_ID)).isEqualTo("NewMsgId"); + assertThat(((BytesMessage) message).getBody(byte[].class)).isEqualTo(testBody); + } + + @Test + public void testPoll_WithTimeout() { + //There is a default timeout value, @see ClientConfig#omsOperationTimeout. + Message message = consumer.receive(); + assertThat(message).isNull(); + + message = consumer.receive(OMS.newKeyValue().put(Message.BuiltinKeys.TIMEOUT, 100)); + assertThat(message).isNull(); + } +} \ No newline at end of file diff --git a/eventmesh-connector-rocketmq/src/test/java/rocketmq/consumer/PushConsumerImplTest.java b/eventmesh-connector-rocketmq/src/test/java/rocketmq/consumer/PushConsumerImplTest.java new file mode 100644 index 0000000000..9315ca11f1 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/test/java/rocketmq/consumer/PushConsumerImplTest.java @@ -0,0 +1,93 @@ +/* + * 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 rocketmq.consumer; + +import com.webank.runtime.configuration.PropInit; +import connector.rocketmq.MessagingAccessPointImpl; +import connector.rocketmq.config.PropInitImpl; +import connector.rocketmq.consumer.PushConsumerImpl; +import connector.rocketmq.domain.NonStandardKeys; +import io.openmessaging.*; +import io.openmessaging.consumer.MessageListener; +import io.openmessaging.consumer.PushConsumer; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.common.message.MessageExt; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.ServiceLoader; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class PushConsumerImplTest { + private PushConsumer consumer; + + @Mock + private DefaultMQPushConsumer rocketmqPushConsumer; + + @Before + public void init() throws NoSuchFieldException, IllegalAccessException { + +// final MessagingAccessPoint messagingAccessPoint = OMS +// .getMessagingAccessPoint("oms:rocketmq://IP1:9876,IP2:9876/namespace"); + ServiceLoader propInitServiceLoader = ServiceLoader.load(PropInit.class); + PropInit p = propInitServiceLoader.iterator().next(); + KeyValue prop = p.initProp().put("ACCESS_POINTS", "IP1:9876,IP2:9876") + .put("REGION", "namespace"); + MessagingAccessPoint messagingAccessPoint = OMS.getMessagingAccessPoint("oms:rocketmq://IP1:9876,IP2:9876/namespace", prop); + consumer = messagingAccessPoint.createPushConsumer( + OMS.newKeyValue().put(OMSBuiltinKeys.CONSUMER_ID, "TestGroup")); + + Field field = PushConsumerImpl.class.getDeclaredField("rocketmqPushConsumer"); + field.setAccessible(true); + DefaultMQPushConsumer innerConsumer = (DefaultMQPushConsumer) field.get(consumer); + field.set(consumer, rocketmqPushConsumer); //Replace + + when(rocketmqPushConsumer.getMessageListener()).thenReturn(innerConsumer.getMessageListener()); + messagingAccessPoint.startup(); + consumer.startup(); + } + + @Test + public void testConsumeMessage() { + final byte[] testBody = new byte[] {'a', 'b'}; + + MessageExt consumedMsg = new MessageExt(); + consumedMsg.setMsgId("NewMsgId"); + consumedMsg.setBody(testBody); + consumedMsg.putUserProperty(NonStandardKeys.MESSAGE_DESTINATION, "TOPIC"); + consumedMsg.setTopic("HELLO_QUEUE"); + consumer.attachQueue("HELLO_QUEUE", new MessageListener() { + @Override + public void onReceived(Message message, Context context) { + assertThat(message.sysHeaders().getString(Message.BuiltinKeys.MESSAGE_ID)).isEqualTo("NewMsgId"); + assertThat(((BytesMessage) message).getBody(byte[].class)).isEqualTo(testBody); + context.ack(); + } + }); + ((MessageListenerConcurrently) rocketmqPushConsumer + .getMessageListener()).consumeMessage(Collections.singletonList(consumedMsg), null); + } +} \ No newline at end of file diff --git a/eventmesh-connector-rocketmq/src/test/java/rocketmq/producer/ProducerImplTest.java b/eventmesh-connector-rocketmq/src/test/java/rocketmq/producer/ProducerImplTest.java new file mode 100644 index 0000000000..e7cebace31 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/test/java/rocketmq/producer/ProducerImplTest.java @@ -0,0 +1,103 @@ +/* + * 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 rocketmq.producer; + +import connector.rocketmq.producer.AbstractOMSProducer; +import io.openmessaging.MessagingAccessPoint; +import io.openmessaging.OMS; +import io.openmessaging.exception.OMSRuntimeException; +import io.openmessaging.producer.Producer; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.lang.reflect.Field; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ProducerImplTest { + private Producer producer; + + @Mock + private DefaultMQProducer rocketmqProducer; + + @Before + public void init() throws NoSuchFieldException, IllegalAccessException { + final MessagingAccessPoint messagingAccessPoint = OMS + .getMessagingAccessPoint("oms:rocketmq://IP1:9876,IP2:9876/namespace"); + producer = messagingAccessPoint.createProducer(); + + Field field = AbstractOMSProducer.class.getDeclaredField("rocketmqProducer"); + field.setAccessible(true); + field.set(producer, rocketmqProducer); + + messagingAccessPoint.startup(); + producer.startup(); + } + + @Test + public void testSend_OK() throws InterruptedException, RemotingException, MQClientException, MQBrokerException { + SendResult sendResult = new SendResult(); + sendResult.setMsgId("TestMsgID"); + sendResult.setSendStatus(SendStatus.SEND_OK); + when(rocketmqProducer.send(any(Message.class), anyLong())).thenReturn(sendResult); + io.openmessaging.producer.SendResult omsResult = + producer.send(producer.createBytesMessage("HELLO_TOPIC", new byte[] {'a'})); + + assertThat(omsResult.messageId()).isEqualTo("TestMsgID"); + } + + @Test + public void testSend_Not_OK() throws InterruptedException, RemotingException, MQClientException, MQBrokerException { + SendResult sendResult = new SendResult(); + sendResult.setSendStatus(SendStatus.FLUSH_DISK_TIMEOUT); + + when(rocketmqProducer.send(any(Message.class), anyLong())).thenReturn(sendResult); + try { + producer.send(producer.createBytesMessage("HELLO_TOPIC", new byte[] {'a'})); + failBecauseExceptionWasNotThrown(OMSRuntimeException.class); + } catch (Exception e) { + assertThat(e).hasMessageContaining("Send message to RocketMQ broker failed."); + } + } + + @Test + public void testSend_WithException() throws InterruptedException, RemotingException, MQClientException, MQBrokerException { + when(rocketmqProducer.send(any(Message.class), anyLong())).thenThrow(MQClientException.class); + try { + producer.send(producer.createBytesMessage("HELLO_TOPIC", new byte[] {'a'})); + failBecauseExceptionWasNotThrown(OMSRuntimeException.class); + } catch (Exception e) { + assertThat(e).hasMessageContaining("Send message to RocketMQ broker failed."); + } + } + +} \ No newline at end of file diff --git a/eventmesh-connector-rocketmq/src/test/java/rocketmq/promise/DefaultPromiseTest.java b/eventmesh-connector-rocketmq/src/test/java/rocketmq/promise/DefaultPromiseTest.java new file mode 100644 index 0000000000..7e674a17a8 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/test/java/rocketmq/promise/DefaultPromiseTest.java @@ -0,0 +1,121 @@ +/* + * 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 rocketmq.promise; + +import connector.rocketmq.promise.DefaultPromise; +import io.openmessaging.Future; +import io.openmessaging.FutureListener; +import io.openmessaging.Promise; +import io.openmessaging.exception.OMSRuntimeException; +import org.junit.Before; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown; + +public class DefaultPromiseTest { + private Promise promise; + + @Before + public void init() { + promise = new DefaultPromise<>(); + } + + @Test + public void testIsCancelled() throws Exception { + assertThat(promise.isCancelled()).isEqualTo(false); + } + + @Test + public void testIsDone() throws Exception { + assertThat(promise.isDone()).isEqualTo(false); + promise.set("Done"); + assertThat(promise.isDone()).isEqualTo(true); + } + + @Test + public void testGet() throws Exception { + promise.set("Done"); + assertThat(promise.get()).isEqualTo("Done"); + } + + @Test + public void testGet_WithTimeout() throws Exception { + try { + promise.get(100); + failBecauseExceptionWasNotThrown(OMSRuntimeException.class); + } catch (OMSRuntimeException e) { + assertThat(e).hasMessageContaining("Get request result is timeout or interrupted"); + } + } + + @Test + public void testAddListener() throws Exception { + promise.addListener(new FutureListener() { + @Override + public void operationComplete(Future future) { + assertThat(promise.get()).isEqualTo("Done"); + + } + }); + promise.set("Done"); + } + + @Test + public void testAddListener_ListenerAfterSet() throws Exception { + promise.set("Done"); + promise.addListener(new FutureListener() { + @Override + public void operationComplete(Future future) { + assertThat(future.get()).isEqualTo("Done"); + } + }); + } + + @Test + public void testAddListener_WithException_ListenerAfterSet() throws Exception { + final Throwable exception = new OMSRuntimeException("-1", "Test Error"); + promise.setFailure(exception); + promise.addListener(new FutureListener() { + @Override + public void operationComplete(Future future) { + assertThat(promise.getThrowable()).isEqualTo(exception); + } + }); + } + + @Test + public void testAddListener_WithException() throws Exception { + final Throwable exception = new OMSRuntimeException("-1", "Test Error"); + promise.addListener(new FutureListener() { + @Override + public void operationComplete(Future future) { + assertThat(promise.getThrowable()).isEqualTo(exception); + } + }); + promise.setFailure(exception); + } + + @Test + public void getThrowable() throws Exception { + assertThat(promise.getThrowable()).isNull(); + Throwable exception = new OMSRuntimeException("-1", "Test Error"); + promise.setFailure(exception); + assertThat(promise.getThrowable()).isEqualTo(exception); + } + +} \ No newline at end of file diff --git a/eventmesh-connector-rocketmq/src/test/java/rocketmq/utils/BeanUtilsTest.java b/eventmesh-connector-rocketmq/src/test/java/rocketmq/utils/BeanUtilsTest.java new file mode 100644 index 0000000000..bf9da12271 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/test/java/rocketmq/utils/BeanUtilsTest.java @@ -0,0 +1,111 @@ +/* + * 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 rocketmq.utils; + +import connector.rocketmq.config.ClientConfig; +import connector.rocketmq.domain.NonStandardKeys; +import connector.rocketmq.utils.BeanUtils; +import io.openmessaging.KeyValue; +import io.openmessaging.OMS; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class BeanUtilsTest { + private KeyValue properties = OMS.newKeyValue(); + + public static class CustomizedConfig extends ClientConfig { + final static String STRING_TEST = "string.test"; + String stringTest = "foobar"; + + final static String DOUBLE_TEST = "double.test"; + double doubleTest = 123.0; + + final static String LONG_TEST = "long.test"; + long longTest = 123L; + + String getStringTest() { + return stringTest; + } + + public void setStringTest(String stringTest) { + this.stringTest = stringTest; + } + + double getDoubleTest() { + return doubleTest; + } + + public void setDoubleTest(final double doubleTest) { + this.doubleTest = doubleTest; + } + + long getLongTest() { + return longTest; + } + + public void setLongTest(final long longTest) { + this.longTest = longTest; + } + + CustomizedConfig() { + } + } + + @Before + public void init() { + properties.put(NonStandardKeys.MAX_REDELIVERY_TIMES, 120); + properties.put(CustomizedConfig.STRING_TEST, "kaka"); + properties.put(NonStandardKeys.CONSUMER_GROUP, "Default_Consumer_Group"); + properties.put(NonStandardKeys.MESSAGE_CONSUME_TIMEOUT, 101); + + properties.put(CustomizedConfig.LONG_TEST, 1234567890L); + properties.put(CustomizedConfig.DOUBLE_TEST, 10.234); + } + + @Test + public void testPopulate() { + CustomizedConfig config = BeanUtils.populate(properties, CustomizedConfig.class); + + //RemotingConfig config = BeanUtils.populate(properties, RemotingConfig.class); + Assert.assertEquals(config.getRmqMaxRedeliveryTimes(), 120); + Assert.assertEquals(config.getStringTest(), "kaka"); + Assert.assertEquals(config.getRmqConsumerGroup(), "Default_Consumer_Group"); + Assert.assertEquals(config.getRmqMessageConsumeTimeout(), 101); + Assert.assertEquals(config.getLongTest(), 1234567890L); + Assert.assertEquals(config.getDoubleTest(), 10.234, 0.000001); + } + + @Test + public void testPopulate_ExistObj() { + CustomizedConfig config = new CustomizedConfig(); + config.setConsumerId("NewConsumerId"); + + Assert.assertEquals(config.getConsumerId(), "NewConsumerId"); + + config = BeanUtils.populate(properties, config); + + //RemotingConfig config = BeanUtils.populate(properties, RemotingConfig.class); + Assert.assertEquals(config.getRmqMaxRedeliveryTimes(), 120); + Assert.assertEquals(config.getStringTest(), "kaka"); + Assert.assertEquals(config.getRmqConsumerGroup(), "Default_Consumer_Group"); + Assert.assertEquals(config.getRmqMessageConsumeTimeout(), 101); + Assert.assertEquals(config.getLongTest(), 1234567890L); + Assert.assertEquals(config.getDoubleTest(), 10.234, 0.000001); + } + +} \ No newline at end of file diff --git a/eventmesh-connector-rocketmq/src/test/resources/META-INF/services/io.openmessaging.MessagingAccessPoint b/eventmesh-connector-rocketmq/src/test/resources/META-INF/services/io.openmessaging.MessagingAccessPoint new file mode 100644 index 0000000000..2c95b00320 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/test/resources/META-INF/services/io.openmessaging.MessagingAccessPoint @@ -0,0 +1 @@ +connector.rocketmq.MessagingAccessPointImpl \ No newline at end of file diff --git a/eventmesh-connector-rocketmq/src/test/resources/META-INF/services/io.openmessaging.producer.Producer b/eventmesh-connector-rocketmq/src/test/resources/META-INF/services/io.openmessaging.producer.Producer new file mode 100644 index 0000000000..88fe45e962 --- /dev/null +++ b/eventmesh-connector-rocketmq/src/test/resources/META-INF/services/io.openmessaging.producer.Producer @@ -0,0 +1 @@ +connector.rocketmq.producer.ProducerImpl \ No newline at end of file diff --git a/eventmesh-emesher/bin/test/asyncPub.sh b/eventmesh-emesher/bin/test/asyncPub.sh new file mode 100644 index 0000000000..28b4c8c798 --- /dev/null +++ b/eventmesh-emesher/bin/test/asyncPub.sh @@ -0,0 +1,90 @@ +#!/bin/sh + + +# Copyright (C) @2017 Webank Group Holding Limited +# +# Licensed 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. +# + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== + +TMP_JAVA_HOME="/nemo/jdk1.8.0_152" + +function is_java8 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' ]] || return 2 + return 0 +} + + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" +elif [[ -d "$JAVA_HOME" ]] && is_java8 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" +elif is_java8 "/nemo/jdk8/bin/java"; then + JAVA="/nemo/jdk8/bin/java"; +elif is_java8 "/nemo/jdk1.8/bin/java"; then + JAVA="/nemo/jdk1.8/bin/java"; +elif is_java8 "/nemo/jdk/bin/java"; then + JAVA="/nemo/jdk/bin/java"; +elif is_java8 "$(which java)"; then + JAVA="$(which java)" +else + echo -e "ERROR\t java(1.8) not found, operation abort." + exit 9; +fi + +echo "proxy use java location= "$JAVA + +PROXY_HOME=`cd "./.." && pwd` + +export PROXY_HOME + +export PROXY_LOG_HOME=${PROXY_HOME}/logs + +echo "PROXY_HOME : ${PROXY_HOME}, PROXY_LOG_HOME : ${PROXY_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${PROXY_LOG_HOME}" ]; then mkdir -p "${PROXY_LOG_HOME}"; fi +} + +error_exit () +{ + echo "ERROR: $1 !!" + exit 1 +} + +export JAVA_HOME + +#=========================================================================================== +# JVM Configuration +#=========================================================================================== +JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx512m -Xmn256m -XX:SurvivorRatio=4" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${PROXY_HOME}/conf/log4j2.xml" +JAVA_OPT="${JAVA_OPT} -Dproxy.log.home=${PROXY_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${PROXY_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" + +make_logs_dir + +echo "using jdk[$JAVA]" >> ${PROXY_LOG_HOME}/defibus-proxy-client.out + +conf=$1 +proxy=$2 +topic=$3 +packetsize=$4 + +ASYNC_REQ_MAIN=cn.webank.emesher.client.sdkdemo.AsyncPublishInstance +$JAVA $JAVA_OPT -classpath ${PROXY_HOME}/conf:${PROXY_HOME}/lib/*:${PROXY_HOME}/apps/* $ASYNC_REQ_MAIN $conf $proxy $topic $packetsize >> ${PROXY_LOG_HOME}/proxy-client.out 2>&1 & +exit 0 diff --git a/eventmesh-emesher/bin/test/asyncRRReq.sh b/eventmesh-emesher/bin/test/asyncRRReq.sh new file mode 100644 index 0000000000..55b652d85e --- /dev/null +++ b/eventmesh-emesher/bin/test/asyncRRReq.sh @@ -0,0 +1,90 @@ +#!/bin/sh + + +# Copyright (C) @2017 Webank Group Holding Limited +# +# Licensed 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. +# + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== + +TMP_JAVA_HOME="/nemo/jdk1.8.0_152" + +function is_java8 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' ]] || return 2 + return 0 +} + + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" +elif [[ -d "$JAVA_HOME" ]] && is_java8 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" +elif is_java8 "/nemo/jdk8/bin/java"; then + JAVA="/nemo/jdk8/bin/java"; +elif is_java8 "/nemo/jdk1.8/bin/java"; then + JAVA="/nemo/jdk1.8/bin/java"; +elif is_java8 "/nemo/jdk/bin/java"; then + JAVA="/nemo/jdk/bin/java"; +elif is_java8 "$(which java)"; then + JAVA="$(which java)" +else + echo -e "ERROR\t java(1.8) not found, operation abort." + exit 9; +fi + +echo "proxy use java location= "$JAVA + +PROXY_HOME=`cd "./.." && pwd` + +export PROXY_HOME + +export PROXY_LOG_HOME=${PROXY_HOME}/logs + +echo "PROXY_HOME : ${PROXY_HOME}, PROXY_LOG_HOME : ${PROXY_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${PROXY_LOG_HOME}" ]; then mkdir -p "${PROXY_LOG_HOME}"; fi +} + +error_exit () +{ + echo "ERROR: $1 !!" + exit 1 +} + +export JAVA_HOME + +#=========================================================================================== +# JVM Configuration +#=========================================================================================== +JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx512m -Xmn256m -XX:SurvivorRatio=4" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${PROXY_HOME}/conf/log4j2.xml" +JAVA_OPT="${JAVA_OPT} -Dproxy.log.home=${PROXY_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${PROXY_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" + +make_logs_dir + +echo "using jdk[$JAVA]" >> ${PROXY_LOG_HOME}/proxy-client.out + +conf=$1 +proxy=$2 +topic=$3 +packetsize=$4 + +ASYNC_RR_REQ_MAIN=cn.webank.emesher.client.sdkdemo.AsyncSyncRequestInstance +$JAVA $JAVA_OPT -classpath ${PROXY_HOME}/conf:${PROXY_HOME}/lib/*:${PROXY_HOME}/apps/* $ASYNC_RR_REQ_MAIN $conf $proxy $topic $packetsize >> ${PROXY_LOG_HOME}/proxy-client.out 2>&1 & +exit 0 diff --git a/eventmesh-emesher/bin/test/syncListen.sh b/eventmesh-emesher/bin/test/syncListen.sh new file mode 100644 index 0000000000..cf1e2eb16d --- /dev/null +++ b/eventmesh-emesher/bin/test/syncListen.sh @@ -0,0 +1,89 @@ +#!/bin/sh + + +# Copyright (C) @2017 Webank Group Holding Limited +# +# Licensed 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. +# + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== + +TMP_JAVA_HOME="/nemo/jdk1.8.0_152" + +function is_java8 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' ]] || return 2 + return 0 +} + + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" +elif [[ -d "$JAVA_HOME" ]] && is_java8 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" +elif is_java8 "/nemo/jdk8/bin/java"; then + JAVA="/nemo/jdk8/bin/java"; +elif is_java8 "/nemo/jdk1.8/bin/java"; then + JAVA="/nemo/jdk1.8/bin/java"; +elif is_java8 "/nemo/jdk/bin/java"; then + JAVA="/nemo/jdk/bin/java"; +elif is_java8 "$(which java)"; then + JAVA="$(which java)" +else + echo -e "ERROR\t java(1.8) not found, operation abort." + exit 9; +fi + +echo "proxy use java location= "$JAVA + +PROXY_HOME=`cd "./.." && pwd` + +export PROXY_HOME + +export PROXY_LOG_HOME=${PROXY_HOME}/logs + +echo "PROXY_HOME : ${PROXY_HOME}, PROXY_LOG_HOME : ${PROXY_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${PROXY_LOG_HOME}" ]; then mkdir -p "${PROXY_LOG_HOME}"; fi +} + +error_exit () +{ + echo "ERROR: $1 !!" + exit 1 +} + +export JAVA_HOME + +#=========================================================================================== +# JVM Configuration +#=========================================================================================== +JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx512m -Xmn256m -XX:SurvivorRatio=4" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${PROXY_HOME}/conf/log4j2.xml" +JAVA_OPT="${JAVA_OPT} -Dproxy.log.home=${PROXY_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${PROXY_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" + +make_logs_dir + +echo "using jdk[$JAVA]" >> ${PROXY_LOG_HOME}/proxy-sdk.out + +proxy=$1 +topic=$2 +threads=$3 + +SYNC_LISTEN_MAIN=cn.webank.emesher.sdk.demo.InstanceSyncListenner +$JAVA $JAVA_OPT -classpath ${PROXY_HOME}/conf:${PROXY_HOME}/lib/*:${PROXY_HOME}/apps/* $SYNC_LISTEN_MAIN $proxy $topic $threads >> ${PROXY_LOG_HOME}/proxy-sdk.out 2>&1 & +exit 0 diff --git a/eventmesh-emesher/bin/test/syncReq.sh b/eventmesh-emesher/bin/test/syncReq.sh new file mode 100644 index 0000000000..3a146cdb44 --- /dev/null +++ b/eventmesh-emesher/bin/test/syncReq.sh @@ -0,0 +1,91 @@ +#!/bin/sh + + +# Copyright (C) @2017 Webank Group Holding Limited +# +# Licensed 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. +# + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== + +TMP_JAVA_HOME="/nemo/jdk1.8.0_152" + +function is_java8 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' ]] || return 2 + return 0 +} + + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" +elif [[ -d "$JAVA_HOME" ]] && is_java8 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" +elif is_java8 "/nemo/jdk8/bin/java"; then + JAVA="/nemo/jdk8/bin/java"; +elif is_java8 "/nemo/jdk1.8/bin/java"; then + JAVA="/nemo/jdk1.8/bin/java"; +elif is_java8 "/nemo/jdk/bin/java"; then + JAVA="/nemo/jdk/bin/java"; +elif is_java8 "$(which java)"; then + JAVA="$(which java)" +else + echo -e "ERROR\t java(1.8) not found, operation abort." + exit 9; +fi + +echo "proxy use java location= "$JAVA + +PROXY_HOME=`cd "./.." && pwd` + +export PROXY_HOME + +export PROXY_LOG_HOME=${PROXY_HOME}/logs + +echo "PROXY_HOME : ${PROXY_HOME}, PROXY_LOG_HOME : ${PROXY_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${PROXY_LOG_HOME}" ]; then mkdir -p "${PROXY_LOG_HOME}"; fi +} + +error_exit () +{ + echo "ERROR: $1 !!" + exit 1 +} + +export JAVA_HOME + +#=========================================================================================== +# JVM Configuration +#=========================================================================================== +JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx512m -Xmn256m -XX:SurvivorRatio=4" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${PROXY_HOME}/conf/log4j2.xml" +JAVA_OPT="${JAVA_OPT} -Dproxy.log.home=${PROXY_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${PROXY_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" + +make_logs_dir + +echo "using jdk[$JAVA]" >> ${PROXY_LOG_HOME}/proxy-client.out + +conf=$1 +proxy=$2 +topic=$3 +packetsize=$4 +threads=$5 + +SYNC_REQ_MAIN=cn.webank.emesher.client.sdkdemo.SyncRequestInstance +$JAVA $JAVA_OPT -classpath ${PROXY_HOME}/conf:${PROXY_HOME}/lib/*:${PROXY_HOME}/apps/* $SYNC_REQ_MAIN $conf $proxy $topic $packetsize $threads >> ${PROXY_LOG_HOME}/proxy-client.out 2>&1 & +exit 0 diff --git a/eventmesh-emesher/src/main/java/cn/webank/defibus/client/impl/factory/DeFiBusClientInstance.java b/eventmesh-emesher/src/main/java/cn/webank/defibus/client/impl/factory/DeFiBusClientInstance.java new file mode 100644 index 0000000000..842ab19e9f --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/defibus/client/impl/factory/DeFiBusClientInstance.java @@ -0,0 +1,234 @@ +/* + * 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 cn.webank.defibus.client.impl.factory; + +import cn.webank.defibus.client.impl.DeFiBusClientAPIImpl; +import cn.webank.defibus.client.impl.DeFiBusClientRemotingProcessor; +import cn.webank.defibus.common.protocol.DeFiBusRequestCode; +import cn.webank.emesher.threads.ThreadPoolHelper; +import org.apache.commons.lang3.RandomUtils; +import org.apache.rocketmq.client.ClientConfig; +import org.apache.rocketmq.client.consumer.store.ReadOffsetType; +import org.apache.rocketmq.client.impl.ClientRemotingProcessor; +import org.apache.rocketmq.client.impl.MQClientAPIImpl; +import org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl; +import org.apache.rocketmq.client.impl.consumer.MQConsumerInner; +import org.apache.rocketmq.client.impl.consumer.ProcessQueue; +import org.apache.rocketmq.client.impl.factory.MQClientInstance; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.remoting.RPCHook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; + +public class DeFiBusClientInstance extends MQClientInstance { + private final ClientConfig clientConfig; + private DeFiBusClientAPIImpl defibusClientAPI; + private ClientRemotingProcessor clientRemotingProcessor; + private DeFiBusClientRemotingProcessor defibusClientRemotingProcessor; + private ExecutorService executorService; + private ScheduledExecutorService scheduledExecutorService; + + private static final Logger LOGGER = LoggerFactory.getLogger(DeFiBusClientInstance.class); + + public DeFiBusClientInstance(ClientConfig clientConfig, int instanceIndex, String clientId) { + this(clientConfig, instanceIndex, clientId, null); + } + + public DeFiBusClientInstance(ClientConfig clientConfig, int instanceIndex, String clientId, RPCHook rpcHook) { + super(clientConfig, instanceIndex, clientId, rpcHook); + this.clientConfig = clientConfig; + try { + + Field processorField = MQClientInstance.class.getDeclaredField("clientRemotingProcessor"); + processorField.setAccessible(true); + clientRemotingProcessor = (ClientRemotingProcessor) processorField.get(this); + + defibusClientRemotingProcessor = new DeFiBusClientRemotingProcessor(this); + + defibusClientAPI = new DeFiBusClientAPIImpl( + super.getNettyClientConfig(), + clientRemotingProcessor, + rpcHook, + clientConfig); + + MQClientAPIImpl mQClientAPIImpl = getMQClientAPIImpl(); + Field mqClientAPIField = MQClientInstance.class.getDeclaredField("mQClientAPIImpl"); + mqClientAPIField.setAccessible(true); + mqClientAPIField.set(this, defibusClientAPI); + mQClientAPIImpl.shutdown(); + + if (this.clientConfig.getNamesrvAddr() != null) { + this.defibusClientAPI.updateNameServerAddressList(this.clientConfig.getNamesrvAddr()); + LOGGER.info("user specified name server address: {}", this.clientConfig.getNamesrvAddr()); + } + + executorService = ThreadPoolHelper.getClientExecutorService(); + scheduledExecutorService = ThreadPoolHelper.getClientScheduledExecutorService(); + + super.getMQClientAPIImpl().getRemotingClient() + .registerProcessor(DeFiBusRequestCode.PUSH_RR_REPLY_MSG_TO_CLIENT, defibusClientRemotingProcessor, executorService); + + super.getMQClientAPIImpl().getRemotingClient() + .registerProcessor(DeFiBusRequestCode.NOTIFY_WHEN_TOPIC_CONFIG_CHANGE, defibusClientRemotingProcessor, executorService); + + super.getMQClientAPIImpl().getRemotingClient() + .registerProcessor(RequestCode.GET_CONSUMER_RUNNING_INFO, clientRemotingProcessor, executorService); + super.getMQClientAPIImpl().getRemotingClient() + .registerProcessor(RequestCode.NOTIFY_CONSUMER_IDS_CHANGED, clientRemotingProcessor, executorService); + super.getMQClientAPIImpl().getRemotingClient() + .registerProcessor(RequestCode.RESET_CONSUMER_CLIENT_OFFSET, clientRemotingProcessor, executorService); + } catch (Exception e) { + LOGGER.warn("failed to initialize factory in mqclient manager.", e); + } + + } + + @Override + public void shutdown() { + this.scheduledExecutorService.shutdown(); + super.shutdown(); + this.executorService.shutdown(); + } + + @Override + public List findConsumerIdList(final String topic, final String group) { + String brokerAddr = this.findBrokerAddrByTopic(topic); + if (null == brokerAddr) { + this.updateTopicRouteInfoFromNameServer(topic); + brokerAddr = this.findBrokerAddrByTopic(topic); + } + + if (null != brokerAddr) { + try { + LOGGER.debug("findConsumerIdList of {} from broker {}", topic, brokerAddr); + List cidList = defibusClientAPI.getConsumerIdListByGroupAndTopic(brokerAddr, group, topic, 3000); + if (cidList != null && !cidList.isEmpty()) { + return cidList; + } + } catch (Exception e) { + LOGGER.warn("getConsumerIdListByGroup failed, " + brokerAddr + " " + group + ", retry immediately"); + } + + String lastSelected = brokerAddr; + brokerAddr = this.findAnotherBrokerAddrByTopic(topic, lastSelected); + if (null == brokerAddr) { + this.updateTopicRouteInfoFromNameServer(topic); + brokerAddr = this.findAnotherBrokerAddrByTopic(topic, lastSelected); + } + if (null != brokerAddr) { + try { + LOGGER.debug("findConsumerIdList of {} from broker {}", topic, brokerAddr); + List cidList = defibusClientAPI.getConsumerIdListByGroupAndTopic(brokerAddr, group, topic, 3000); + return cidList; + } catch (Exception e) { + LOGGER.warn("getConsumerIdListByGroup failed, " + brokerAddr + " " + group + ", after retry ", e); + } + } + } + + return null; + } + + private String findAnotherBrokerAddrByTopic(String topic, String lastSelected) { + TopicRouteData topicRouteData = this.getTopicRouteTable().get(topic); + if (topicRouteData != null && topicRouteData.getBrokerDatas() != null) { + List allBrokers = topicRouteData.getBrokerDatas(); + for (BrokerData bd : allBrokers) { + if (!bd.selectBrokerAddr().equals(lastSelected)) { + String addr = bd.selectBrokerAddr(); + LOGGER.debug("find another broker addr by topic [{}], find addr: {}, lastSelected: {}", topic, addr, lastSelected); + return addr; + } + } + + if (!allBrokers.isEmpty()) { + int index = RandomUtils.nextInt(0, allBrokers.size()); + BrokerData bd = allBrokers.get(index % allBrokers.size()); + String addr = bd.selectBrokerAddr(); + LOGGER.debug("find any broker addr by topic [{}], find addr: {}, lastSelected: {}", topic, addr, lastSelected); + return addr; + } + } + return null; + } + + public ScheduledExecutorService getScheduledExecutorService() { + return scheduledExecutorService; + } + + @Override + public synchronized void resetOffset(String topic, String group, Map offsetTable) { + DefaultMQPushConsumerImpl consumer = null; + try { + MQConsumerInner impl = this.selectConsumer(group); + if (impl != null && impl instanceof DefaultMQPushConsumerImpl) { + consumer = (DefaultMQPushConsumerImpl) impl; + } else { + LOGGER.info("[reset-offset] consumer dose not exist. group={}", group); + return; + } + + ConcurrentMap processQueueTable = consumer.getRebalanceImpl().getProcessQueueTable(); + for (Map.Entry entry : processQueueTable.entrySet()) { + MessageQueue mq = entry.getKey(); + if (topic.equals(mq.getTopic()) && offsetTable.containsKey(mq)) { + ProcessQueue pq = entry.getValue(); + pq.setDropped(true); + pq.clear(); + LOGGER.info("[reset-offset] drop process queue, {}", mq); + } + } + + Iterator iterator = processQueueTable.keySet().iterator(); + while (iterator.hasNext()) { + MessageQueue mq = iterator.next(); + Long offset = offsetTable.get(mq); + if (topic.equals(mq.getTopic()) && offset != null) { + try { + long currentOffset = consumer.getOffsetStore().readOffset(mq, ReadOffsetType.READ_FROM_MEMORY); + consumer.updateConsumeOffset(mq, offset); + consumer.getRebalanceImpl().removeUnnecessaryMessageQueue(mq, processQueueTable.get(mq)); + iterator.remove(); + LOGGER.info("[reset-offset] update offset from {} to {} and remove mq, {}", currentOffset, offset, mq); + } catch (Exception e) { + LOGGER.warn("reset offset failed. group={}, {}", group, mq, e); + } + } + } + } finally { + if (consumer != null) { + consumer.doRebalance(); + } + } + } + + public ExecutorService getExecutorService() { + return executorService; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/admin/controller/ClientManageController.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/admin/controller/ClientManageController.java new file mode 100644 index 0000000000..1031d3effa --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/admin/controller/ClientManageController.java @@ -0,0 +1,796 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/admin/controller/ClientManageController.java +package cn.webank.emesher.admin.controller; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.ProxyTcp2Client; +import cn.webank.emesher.core.protocol.tcp.client.group.ClientGroupWrapper; +import cn.webank.emesher.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import cn.webank.emesher.core.protocol.tcp.client.group.dispatch.DownstreamDispatchStrategy; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.emesher.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.admin.controller; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.tcp.client.ProxyTcp2Client; +import com.webank.runtime.core.protocol.tcp.client.group.ClientGroupWrapper; +import com.webank.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import com.webank.runtime.core.protocol.tcp.client.group.dispatch.DownstreamDispatchStrategy; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.runtime.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import com.webank.runtime.util.ProxyUtil; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/admin/controller/ClientManageController.java +import com.alibaba.fastjson.JSON; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.InetSocketAddress; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +public class ClientManageController { + + private static final Logger logger = LoggerFactory.getLogger(ClientManageController.class); + + private ProxyTCPServer proxyTCPServer; + + public ClientManageController(ProxyTCPServer proxyTCPServer){ + this.proxyTCPServer = proxyTCPServer; + } + + public void start() throws IOException { + int port = proxyTCPServer.getEventMeshConfiguration().proxyServerAdminPort; + HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); + server.createContext("/clientManage/showClient", new ShowClientHandler()); + server.createContext("/clientManage/showClientBySystemAndDcn", new ShowClientBySystemAndDcnHandler()); + server.createContext("/clientManage/rejectAllClient", new RejectAllClientHandler()); + server.createContext("/clientManage/rejectClientByIpPort", new RejectClientByIpPortHandler()); + server.createContext("/clientManage/rejectClientBySubSystem", new RejectClientBySubSystemHandler()); + server.createContext("/clientManage/redirectClientBySubSystem", new RedirectClientBySubSystemHandler()); + server.createContext("/clientManage/redirectClientByPath", new RedirectClientByPathHandler()); + server.createContext("/clientManage/redirectClientByIpPort", new RedirectClientByIpPortHandler()); + server.createContext("/proxy/msg/push", new ProxyMsgDownStreamHandler()); + server.createContext("/clientManage/showListenClientByTopic", new ShowListenClientByTopicHandler()); + + server.start(); + logger.info("ClientManageController start success, port:{}", port); + } + + private Map parsePostParameters(HttpExchange exchange) + throws IOException { + Map parameters = new HashMap<>(); + if ("post".equalsIgnoreCase(exchange.getRequestMethod())) { + //parameters = (Map)exchange.getAttribute("parameters"); + InputStreamReader isr = + new InputStreamReader(exchange.getRequestBody(),"utf-8"); + BufferedReader br = new BufferedReader(isr); + String query = br.readLine(); + parseQuery(query, parameters); + } + return parameters; + } + + @SuppressWarnings("unchecked") + private void parseQuery(String query, Map parameters) + throws UnsupportedEncodingException { + + if (query != null) { + String pairs[] = query.split("&"); + + for (String pair : pairs) { + String param[] = pair.split("="); + + String key = null; + String value = null; + if (param.length > 0) { + key = URLDecoder.decode(param[0],"UTF-8"); + } + + if (param.length > 1) { + value = URLDecoder.decode(param[1],"UTF-8"); + } + + if (parameters.containsKey(key)) { + Object obj = parameters.get(key); + if(obj instanceof List) { + List values = (List)obj; + values.add(value); + } else if(obj instanceof String) { + List values = new ArrayList(); + values.add((String)obj); + values.add(value); + parameters.put(key, values); + } + } else { + parameters.put(key, value); + } + } + } + } + + /** + * 打印本proxy上所有客户端信息 + * + * @return + */ + class ShowClientHandler implements HttpHandler{ + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String result = ""; + OutputStream out = httpExchange.getResponseBody(); + try{ + String newLine = System.getProperty("line.separator"); + logger.info("showAllClient================="); + ClientSessionGroupMapping clientSessionGroupMapping = proxyTCPServer.getClientSessionGroupMapping(); + Map dcnSystemMap = clientSessionGroupMapping.statDCNSystemInfo(); + if (!dcnSystemMap.isEmpty()) { + List> list = new ArrayList<>(); + ValueComparator vc = new ValueComparator(); + for (Map.Entry entry : dcnSystemMap.entrySet()) { + list.add(entry); + } + Collections.sort(list, vc); + for (Map.Entry entry : list) { + result += String.format("System=%s | ClientNum=%d", entry.getKey(), entry.getValue().intValue()) + + newLine; + } + } + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + }catch (Exception e){ + logger.error("ShowClientHandler fail...", e); + }finally { + if(out != null){ + try { + out.close(); + }catch (IOException e){ + logger.warn("out close failed...", e); + } + } + } + + } + } + + class ValueComparator implements Comparator> { + @Override + public int compare(Map.Entry x, Map.Entry y) { + return x.getValue().intValue() - y.getValue().intValue(); + } + } + + /** + * 根据子系统号和DCN打印客户端信息 + * + * @return + */ + class ShowClientBySystemAndDcnHandler implements HttpHandler{ + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String result = ""; + OutputStream out = httpExchange.getResponseBody(); + try{ + String queryString = httpExchange.getRequestURI().getQuery(); + Map queryStringInfo = formData2Dic(queryString); + String dcn = queryStringInfo.get(ProxyConstants.MANAGE_DCN); + String subSystem = queryStringInfo.get(ProxyConstants.MANAGE_SUBSYSTEM); + + String newLine = System.getProperty("line.separator"); + logger.info("showClientBySubsysAndDcn,subsys:{},dcn:{}=================",subSystem,dcn); + ClientSessionGroupMapping clientSessionGroupMapping = proxyTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + if (!sessionMap.isEmpty()) { + for (Session session : sessionMap.values()) { + if (session.getClient().getDcn().equals(dcn) && session.getClient().getSubsystem().equals(subSystem)) { + UserAgent userAgent = session.getClient(); + result += String.format("pid=%s | ip=%s | port=%s | path=%s | purpose=%s", userAgent.getPid(), userAgent + .getHost(), userAgent.getPort(), userAgent.getPath(), userAgent.getPurpose()) + newLine; + } + } + } + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + }catch (Exception e){ + logger.error("ShowClientBySystemAndDcnHandler fail...", e); + }finally { + if(out != null){ + try { + out.close(); + }catch (IOException e){ + logger.warn("out close failed...", e); + } + } + } + + } + } + + + /** + * 根据topic查询监听客户端 + * + */ + class ShowListenClientByTopicHandler implements HttpHandler{ + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String result = ""; + OutputStream out = httpExchange.getResponseBody(); + try{ + String queryString = httpExchange.getRequestURI().getQuery(); + Map queryStringInfo = formData2Dic(queryString); + String topic = queryStringInfo.get(ProxyConstants.MANAGE_TOPIC); + + String newLine = System.getProperty("line.separator"); + logger.info("showListeningClientByTopic,topic:{}=================",topic); + ClientSessionGroupMapping clientSessionGroupMapping = proxyTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap clientGroupMap = clientSessionGroupMapping.getClientGroupMap(); + if (!clientGroupMap.isEmpty()) { + for (ClientGroupWrapper cgw : clientGroupMap.values()) { + Set listenSessionSet = cgw.getTopic2sessionInGroupMapping().get(topic); + if (listenSessionSet != null && listenSessionSet.size() > 0) { + result += String.format("group:%s",cgw.getGroupName()) + newLine; + for(Session session : listenSessionSet) { + UserAgent userAgent = session.getClient(); + result += String.format("pid=%s | ip=%s | port=%s | path=%s | version=%s", userAgent.getPid(), userAgent + .getHost(), userAgent.getPort(), userAgent.getPath(), userAgent.getVersion()) + newLine; + } + } + } + } + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + }catch (Exception e){ + logger.error("ShowListenClientByTopicHandler fail...", e); + }finally { + if(out != null){ + try { + out.close(); + }catch (IOException e){ + logger.warn("out close failed...", e); + } + } + } + + } + } + + + /** + * 剔除该proxy上接入的所有C 客户端 + * + * @return + */ + class RejectAllClientHandler implements HttpHandler{ + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String result = ""; + OutputStream out = httpExchange.getResponseBody(); + try{ + ClientSessionGroupMapping clientSessionGroupMapping = proxyTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + final List successRemoteAddrs = new ArrayList(); + try { + logger.info("rejectAllClient in admin===================="); + if (!sessionMap.isEmpty()) { + for (Map.Entry entry : sessionMap.entrySet()) { + InetSocketAddress addr = ProxyTcp2Client.serverGoodby2Client(entry.getValue(), clientSessionGroupMapping); + if (addr != null) { + successRemoteAddrs.add(addr); + } + } + } + } catch (Exception e) { + logger.error("clientManage|rejectAllClient|fail", e); + result = String.format("rejectAllClient fail! sessionMap size {%d}, had reject {%s}, errorMsg : %s", + sessionMap.size(), printClients(successRemoteAddrs), e.getMessage()); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + return; + } + result = String.format("rejectAllClient success! sessionMap size {%d}, had reject {%s}", sessionMap.size + (), printClients(successRemoteAddrs)); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + }catch (Exception e){ + logger.error("rejectAllClient fail...", e); + }finally { + if(out != null){ + try { + out.close(); + }catch (IOException e){ + logger.warn("out close failed...", e); + } + } + } + + } + } + + /** + * IP,PORT 来剔除C客户端 + * + * @return + */ + class RejectClientByIpPortHandler implements HttpHandler{ + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String result = ""; + OutputStream out = httpExchange.getResponseBody(); + try{ + String queryString = httpExchange.getRequestURI().getQuery(); + Map queryStringInfo = formData2Dic(queryString); + String ip = queryStringInfo.get(ProxyConstants.MANAGE_IP); + String port = queryStringInfo.get(ProxyConstants.MANAGE_PORT); + + if (StringUtils.isBlank(ip) || StringUtils.isBlank(port)) { + httpExchange.sendResponseHeaders(200, 0); + result = "params illegal!"; + out.write(result.getBytes()); + return; + } + logger.info("rejectClientByIpPort in admin,ip:{},port:{}====================",ip,port); + ClientSessionGroupMapping clientSessionGroupMapping = proxyTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + final List successRemoteAddrs = new ArrayList(); + try { + if (!sessionMap.isEmpty()) { + for (Map.Entry entry : sessionMap.entrySet()) { + if (entry.getKey().getHostString().equals(ip) && String.valueOf(entry.getKey().getPort()).equals(port)) { + InetSocketAddress addr = ProxyTcp2Client.serverGoodby2Client(entry.getValue(), clientSessionGroupMapping); + if (addr != null) { + successRemoteAddrs.add(addr); + } + } + } + } + } catch (Exception e) { + logger.error("clientManage|rejectClientByIpPort|fail|ip={}|port={},errMsg={}", ip, port, e); + result = String.format("rejectClientByIpPort fail! {ip=%s port=%s}, had reject {%s}, errorMsg : %s", ip, + port, printClients(successRemoteAddrs), e.getMessage()); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + return; + } + + result = String.format("rejectClientByIpPort success! {ip=%s port=%s}, had reject {%s}", ip, port, printClients + (successRemoteAddrs)); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + }catch (Exception e){ + logger.error("rejectClientByIpPort fail...", e); + }finally { + if(out != null){ + try { + out.close(); + }catch (IOException e){ + logger.warn("out close failed...", e); + } + } + } + + } + } + + + /** + * 按DCN和SUBSYSTEMID来剔除C客户端 + * + * @return + */ + class RejectClientBySubSystemHandler implements HttpHandler{ + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String result = ""; + OutputStream out = httpExchange.getResponseBody(); + try{ + String queryString = httpExchange.getRequestURI().getQuery(); + Map queryStringInfo = formData2Dic(queryString); + String dcn = queryStringInfo.get(ProxyConstants.MANAGE_DCN); + String subSystem = queryStringInfo.get(ProxyConstants.MANAGE_SUBSYSTEM); + + if (StringUtils.isBlank(dcn) || StringUtils.isBlank(subSystem)) { + httpExchange.sendResponseHeaders(200, 0); + result = "params illegal!"; + out.write(result.getBytes()); + return; + } + + logger.info("rejectClientBySubSystem in admin,subsys:{},dcn:{}====================",subSystem,dcn); + ClientSessionGroupMapping clientSessionGroupMapping = proxyTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + final List successRemoteAddrs = new ArrayList(); + try { + if (!sessionMap.isEmpty()) { + for (Session session : sessionMap.values()) { + if (session.getClient().getDcn().equals(dcn) && session.getClient().getSubsystem().equals(subSystem)) { + InetSocketAddress addr = ProxyTcp2Client.serverGoodby2Client(session, clientSessionGroupMapping); + if (addr != null) { + successRemoteAddrs.add(addr); + } + } + } + } + } catch (Exception e) { + logger.error("clientManage|rejectClientBySubSystem|fail|dcn={}|subSystemId={},errMsg={}", dcn, subSystem, e); + result = String.format("rejectClientBySubSystem fail! sessionMap size {%d}, had reject {%d} , {dcn=%s " + + "port=%s}, errorMsg : %s", sessionMap.size(), printClients(successRemoteAddrs), dcn, + subSystem, e.getMessage()); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + return; + } + result = String.format("rejectClientBySubSystem success! sessionMap size {%d}, had reject {%s} , {dcn=%s " + + "port=%s}", sessionMap.size(), printClients(successRemoteAddrs), dcn, subSystem); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + }catch (Exception e){ + logger.error("rejectClientBySubSystem fail...", e); + }finally { + if(out != null){ + try { + out.close(); + }catch (IOException e){ + logger.warn("out close failed...", e); + } + } + } + + } + } + + /** + * 子系统重定向,for 子系统和DCN + * + * @return + */ + class RedirectClientBySubSystemHandler implements HttpHandler{ + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String result = ""; + OutputStream out = httpExchange.getResponseBody(); + try{ + String queryString = httpExchange.getRequestURI().getQuery(); + Map queryStringInfo = formData2Dic(queryString); + String dcn = queryStringInfo.get(ProxyConstants.MANAGE_DCN); + String subSystem = queryStringInfo.get(ProxyConstants.MANAGE_SUBSYSTEM); + String destProxyIp = queryStringInfo.get(ProxyConstants.MANAGE_DEST_IP); + String destProxyPort = queryStringInfo.get(ProxyConstants.MANAGE_DEST_PORT); + + if (StringUtils.isBlank(dcn) || !StringUtils.isNumeric(subSystem) + || StringUtils.isBlank(destProxyIp) || StringUtils.isBlank(destProxyPort) + || !StringUtils.isNumeric(destProxyPort)) { + httpExchange.sendResponseHeaders(200, 0); + result = "params illegal!"; + out.write(result.getBytes()); + return; + } + logger.info("redirectClientBySubSystem in admin,subsys:{},dcn:{},destIp:{},destPort:{}====================",subSystem,dcn,destProxyIp,destProxyPort); + ClientSessionGroupMapping clientSessionGroupMapping = proxyTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + String redirectResult = ""; + try { + if (!sessionMap.isEmpty()) { + for (Session session : sessionMap.values()) { + if (session.getClient().getDcn().equals(dcn) && session.getClient().getSubsystem().equals(subSystem)) { + redirectResult += "|"; + redirectResult += ProxyTcp2Client.redirectClient2NewProxy(destProxyIp, Integer.parseInt(destProxyPort), + session, clientSessionGroupMapping); + } + } + } + } catch (Exception e) { + logger.error("clientManage|redirectClientBySubSystem|fail|dcn={}|subSystem={}|destProxyIp" + + "={}|destProxyPort={},errMsg={}", dcn, subSystem, destProxyIp, destProxyPort, e); + result = String.format("redirectClientBySubSystem fail! sessionMap size {%d}, {clientIp=%s clientPort=%s " + + "destProxyIp=%s destProxyPort=%s}, result {%s}, errorMsg : %s", + sessionMap.size(), dcn, subSystem, destProxyIp, destProxyPort, redirectResult, e + .getMessage()); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + return; + } + result = String.format("redirectClientBySubSystem success! sessionMap size {%d}, {dcn=%s subSystem=%s " + + "destProxyIp=%s destProxyPort=%s}, result {%s} ", + sessionMap.size(), dcn, subSystem, destProxyIp, destProxyPort, redirectResult); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + }catch (Exception e){ + logger.error("redirectClientBySubSystem fail...", e); + }finally { + if(out != null){ + try { + out.close(); + }catch (IOException e){ + logger.warn("out close failed...", e); + } + } + } + + } + } + + /** + * 子系统重定向,for path + * + * @return + */ + class RedirectClientByPathHandler implements HttpHandler{ + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String result = ""; + OutputStream out = httpExchange.getResponseBody(); + try{ + String queryString = httpExchange.getRequestURI().getQuery(); + Map queryStringInfo = formData2Dic(queryString); + String path = queryStringInfo.get(ProxyConstants.MANAGE_PATH); + String destProxyIp = queryStringInfo.get(ProxyConstants.MANAGE_DEST_IP); + String destProxyPort = queryStringInfo.get(ProxyConstants.MANAGE_DEST_PORT); + + if (StringUtils.isBlank(path) || StringUtils.isBlank(destProxyIp) || StringUtils.isBlank(destProxyPort) || + !StringUtils.isNumeric(destProxyPort)) { + httpExchange.sendResponseHeaders(200, 0); + result = "params illegal!"; + out.write(result.getBytes()); + return; + } + logger.info("redirectClientByPath in admin,path:{},destIp:{},destPort:{}====================",path,destProxyIp,destProxyPort); + ClientSessionGroupMapping clientSessionGroupMapping = proxyTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + String redirectResult = ""; + try { + if (!sessionMap.isEmpty()) { + for (Session session : sessionMap.values()) { + if (session.getClient().getPath().contains(path)) { + redirectResult += "|"; + redirectResult += ProxyTcp2Client.redirectClient2NewProxy(destProxyIp, Integer.parseInt(destProxyPort), + session, clientSessionGroupMapping); + } + } + } + } catch (Exception e) { + logger.error("clientManage|redirectClientByPath|fail|path={}|destProxyIp" + + "={}|destProxyPort={},errMsg={}", path, destProxyIp, destProxyPort, e); + result = String.format("redirectClientByPath fail! sessionMap size {%d}, {path=%s " + + "destProxyIp=%s destProxyPort=%s}, result {%s}, errorMsg : %s", + sessionMap.size(), path, destProxyIp, destProxyPort, redirectResult, e + .getMessage()); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + return; + } + result = String.format("redirectClientByPath success! sessionMap size {%d}, {path=%s " + + "destProxyIp=%s destProxyPort=%s}, result {%s} ", + sessionMap.size(), path, destProxyIp, destProxyPort, redirectResult); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + }catch (Exception e){ + logger.error("redirectClientByPath fail...", e); + }finally { + if(out != null){ + try { + out.close(); + }catch (IOException e){ + logger.warn("out close failed...", e); + } + } + } + + } + } + + /** + * 子系统重定向,for ip和port + * + * @return + */ + class RedirectClientByIpPortHandler implements HttpHandler{ + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String result = ""; + OutputStream out = httpExchange.getResponseBody(); + try{ + String queryString = httpExchange.getRequestURI().getQuery(); + Map queryStringInfo = formData2Dic(queryString); + String ip = queryStringInfo.get(ProxyConstants.MANAGE_IP); + String port = queryStringInfo.get(ProxyConstants.MANAGE_PORT); + String destProxyIp = queryStringInfo.get(ProxyConstants.MANAGE_DEST_IP); + String destProxyPort = queryStringInfo.get(ProxyConstants.MANAGE_DEST_PORT); + + if (StringUtils.isBlank(ip) || !StringUtils.isNumeric(port) + || StringUtils.isBlank(destProxyIp) || StringUtils.isBlank(destProxyPort) + || !StringUtils.isNumeric(destProxyPort)) { + httpExchange.sendResponseHeaders(200, 0); + result = "params illegal!"; + out.write(result.getBytes()); + return; + } + logger.info("redirectClientByIpPort in admin,ip:{},port:{},destIp:{},destPort:{}====================",ip,port,destProxyIp,destProxyPort); + ClientSessionGroupMapping clientSessionGroupMapping = proxyTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + String redirectResult = ""; + try { + if (!sessionMap.isEmpty()) { + for (Session session : sessionMap.values()) { + if (session.getClient().getHost().equals(ip) && String.valueOf(session.getClient().getPort()).equals(port)) { + redirectResult += "|"; + redirectResult += ProxyTcp2Client.redirectClient2NewProxy(destProxyIp, Integer.parseInt(destProxyPort), + session, clientSessionGroupMapping); + } + } + } + } catch (Exception e) { + logger.error("clientManage|redirectClientByIpPort|fail|ip={}|port={}|destProxyIp" + + "={}|destProxyPort={},errMsg={}", ip, port, destProxyIp, destProxyPort, e); + result = String.format("redirectClientByIpPort fail! sessionMap size {%d}, {clientIp=%s clientPort=%s " + + "destProxyIp=%s destProxyPort=%s}, result {%s}, errorMsg : %s", + sessionMap.size(), ip, port, destProxyIp, destProxyPort, redirectResult, e + .getMessage()); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + return; + } + result = String.format("redirectClientByIpPort success! sessionMap size {%d}, {ip=%s port=%s " + + "destProxyIp=%s destProxyPort=%s}, result {%s} ", + sessionMap.size(), ip, port, destProxyIp, destProxyPort, redirectResult); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + }catch (Exception e){ + logger.error("redirectClientByIpPort fail...", e); + }finally { + if(out != null){ + try { + out.close(); + }catch (IOException e){ + logger.warn("out close failed...", e); + } + } + } + + } + } + + private String printClients(List clients) { + if (clients.isEmpty()) { + return "no session had been closed"; + } + StringBuffer sb = new StringBuffer(); + for (InetSocketAddress addr : clients) { + sb.append(addr).append("|"); + } + return sb.toString(); + } + + private Map formData2Dic(String formData) { + Map result = new HashMap<>(); + if(formData== null || formData.trim().length() == 0) { + return result; + } + final String[] items = formData.split("&"); + Arrays.stream(items).forEach(item ->{ + final String[] keyAndVal = item.split("="); + if( keyAndVal.length == 2) { + try{ + final String key = URLDecoder.decode( keyAndVal[0],"utf8"); + final String val = URLDecoder.decode( keyAndVal[1],"utf8"); + result.put(key,val); + }catch (UnsupportedEncodingException e) { + logger.warn("formData2Dic:param decode failed...", e); + } + } + }); + return result; + } + + class ProxyMsgDownStreamHandler implements HttpHandler{ + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String result = "false"; + OutputStream out = httpExchange.getResponseBody(); + try{ + Map queryStringInfo = parsePostParameters(httpExchange); + String msgStr = (String)queryStringInfo.get("msg"); + String groupName = (String)queryStringInfo.get("group"); + logger.info("recieve msg from other proxy, group:{}, msg:{}", groupName, msgStr); + if (StringUtils.isBlank(msgStr) || StringUtils.isBlank(groupName)) { + logger.warn("msg or groupName is null"); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + return; + } + MessageExt messageExt = JSON.parseObject(msgStr, MessageExt.class); + String topic = messageExt.getTopic(); + + if (!ProxyUtil.isValidRMBTopic(topic)) { + logger.warn("msg topic is illegal"); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + return; + } + + DownstreamDispatchStrategy downstreamDispatchStrategy = proxyTCPServer.getClientSessionGroupMapping().getClientGroupWrapper(groupName).getDownstreamDispatchStrategy(); + Set groupConsumerSessions = proxyTCPServer.getClientSessionGroupMapping().getClientGroupWrapper(groupName).getGroupConsumerSessions(); + Session session = downstreamDispatchStrategy.select(groupName, topic, groupConsumerSessions); + + if(session == null){ + logger.error("DownStream msg,retry other proxy found no session again"); + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + return; + } + + DownStreamMsgContext downStreamMsgContext = + new DownStreamMsgContext(messageExt, session, proxyTCPServer.getClientSessionGroupMapping().getClientGroupWrapper(groupName).getPersistentMsgConsumer(), null, true); + proxyTCPServer.getClientSessionGroupMapping().getClientGroupWrapper(groupName).getDownstreamMap().putIfAbsent(downStreamMsgContext.seq, downStreamMsgContext); + + if (session.isCanDownStream()) { + session.downstreamMsg(downStreamMsgContext); + httpExchange.sendResponseHeaders(200, 0); + result = "true"; + out.write(result.getBytes()); + return; + } + + logger.warn("ProxyMsgDownStreamHandler|dispatch retry, seq[{}]", downStreamMsgContext.seq); + long delayTime = ProxyUtil.isService(downStreamMsgContext.msgExt.getTopic()) ? 0 : proxyTCPServer.getAccessConfiguration().proxyTcpMsgRetryDelayInMills; + downStreamMsgContext.delay(delayTime); + proxyTCPServer.getProxyTcpRetryer().pushRetry(downStreamMsgContext); + result = "true"; + httpExchange.sendResponseHeaders(200, 0); + out.write(result.getBytes()); + + }catch (Exception e){ + logger.error("ProxyMsgDownStreamHandler handle fail...", e); + }finally { + if(out != null){ + try { + out.close(); + }catch (IOException e){ + logger.warn("out close failed...", e); + } + } + } + + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/AbrstractHTTPServer.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/AbrstractHTTPServer.java new file mode 100644 index 0000000000..e63602c562 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/AbrstractHTTPServer.java @@ -0,0 +1,434 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/boot/AbrstractHTTPServer.java +package cn.webank.emesher.boot; +======== +package com.webank.runtime.boot; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/boot/AbrstractHTTPServer.java + +import cn.webank.emesher.common.Pair; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.emesher.core.protocol.http.processor.inf.HttpRequestProcessor; +import cn.webank.eventmesh.common.ThreadPoolFactory; +import cn.webank.eventmesh.common.command.HttpCommand; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import cn.webank.emesher.metrics.http.HTTPMetricsServer; +import cn.webank.emesher.util.ProxyUtil; +import com.google.common.base.Preconditions; +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/boot/AbrstractHTTPServer.java +======== +import com.webank.runtime.common.Pair; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import com.webank.runtime.metrics.http.HTTPMetricsServer; +import com.webank.runtime.util.ProxyUtil; +import com.webank.eventmesh.common.ThreadPoolFactory; +import com.webank.eventmesh.common.command.HttpCommand; +import com.webank.eventmesh.common.protocol.http.body.Body; +import com.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import com.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import com.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +import com.webank.eventmesh.common.protocol.http.header.Header; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/boot/AbrstractHTTPServer.java +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.QueryStringDecoder; +import io.netty.handler.codec.http.multipart.Attribute; +import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; +import io.netty.handler.codec.http.multipart.DiskAttribute; +import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; +import io.netty.handler.codec.http.multipart.InterfaceHttpData; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +public abstract class AbrstractHTTPServer extends AbstractRemotingServer { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public Logger httpLogger = LoggerFactory.getLogger("http"); + + public HTTPMetricsServer metrics; + + public DefaultHttpDataFactory defaultHttpDataFactory = new DefaultHttpDataFactory(false); + + private AtomicBoolean started = new AtomicBoolean(false); + + public ThreadPoolExecutor asyncContextCompleteHandler = + ThreadPoolFactory.createThreadPoolExecutor(10, 10, "proxy-http-asyncContext-"); + + static { + DiskAttribute.deleteOnExitTemporaryFile = false; + } + + protected HashMap> processorTable = + new HashMap>(64); + + public AbrstractHTTPServer(int port) { + this.port = port; + } + + public Map parseHTTPHeader(HttpRequest fullReq) { + Map headerParam = new HashMap<>(); + for (String key : fullReq.headers().names()) { + if (StringUtils.equalsIgnoreCase(HttpHeaderNames.CONTENT_TYPE.toString(), key) + || StringUtils.equalsIgnoreCase(HttpHeaderNames.ACCEPT_ENCODING.toString(), key) + || StringUtils.equalsIgnoreCase(HttpHeaderNames.CONTENT_LENGTH.toString(), key)) { + continue; + } + headerParam.put(key, fullReq.headers().get(key)); + } + return headerParam; + } + + public void sendError(ChannelHandlerContext ctx, + HttpResponseStatus status) { + FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, + status); + response.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN + + "; charset=" + ProxyConstants.DEFAULT_CHARSET); + response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); + response.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + } + + public void sendResponse(ChannelHandlerContext ctx, + DefaultFullHttpResponse response) { + ctx.writeAndFlush(response).addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture f) throws Exception { + if (!f.isSuccess()) { + httpLogger.warn("send response to [{}] fail, will close this channel", RemotingHelper.parseChannelRemoteAddr(f.channel())); + f.channel().close(); + return; + } + } + }); + } + + @Override + public void start() throws Exception { + super.start(); + Runnable r = () -> { + ServerBootstrap b = new ServerBootstrap(); + b.group(this.bossGroup, this.workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) + throws Exception { + ch.pipeline() + .addLast(new HttpRequestDecoder(), + new HttpResponseEncoder(), + new HttpConnectionHandler(), + new HttpObjectAggregator(Integer.MAX_VALUE), + new HTTPHandler()); + } + }).childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE); + try { + logger.info("HTTPServer[port={}] started......", this.port); + ChannelFuture future = b.bind(this.port).sync(); + future.channel().closeFuture().sync(); + } catch (Exception e) { + logger.error("HTTPServer start Err!", e); + try { + shutdown(); + } catch (Exception e1) { + logger.error("HTTPServer shutdown Err!", e); + } + return; + } + }; + + Thread t = new Thread(r, "proxy-http-server"); + t.start(); + started.compareAndSet(false, true); + } + + @Override + public void init(String threadPrefix) throws Exception { + super.init(threadPrefix); + } + + @Override + public void shutdown() throws Exception { + super.shutdown(); + started.compareAndSet(true, false); + } + + public void registerProcessor(Integer requestCode, HttpRequestProcessor processor, ThreadPoolExecutor executor) { + Preconditions.checkState(ObjectUtils.allNotNull(requestCode), "requestCode can't be null"); + Preconditions.checkState(ObjectUtils.allNotNull(processor), "processor can't be null"); + Preconditions.checkState(ObjectUtils.allNotNull(executor), "executor can't be null"); + Pair pair = new Pair(processor, executor); + this.processorTable.put(requestCode, pair); + } + + class HTTPHandler extends SimpleChannelInboundHandler { + + @Override + protected void channelRead0(ChannelHandlerContext ctx, HttpRequest httpRequest) throws Exception { + HttpPostRequestDecoder decoder = null; + try { + if (!httpRequest.decoderResult().isSuccess()) { + sendError(ctx, HttpResponseStatus.BAD_REQUEST); + return; + } + + final HttpCommand requestCommand = new HttpCommand(); + + httpRequest.headers().set(ProtocolKey.ClientInstanceKey.IP, RemotingHelper.parseChannelRemoteAddr(ctx.channel())); + + String protocolVersion = StringUtils.deleteWhitespace(httpRequest.headers().get(ProtocolKey.VERSION)); + if (StringUtils.isBlank(protocolVersion)) { + protocolVersion = ProtocolVersion.V1.getVersion(); + httpRequest.headers().set(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()); + } + + metrics.summaryMetrics.recordHTTPRequest(); + + long bodyDecodeStart = System.currentTimeMillis(); + + Map bodyMap = new HashMap<>(); + + if (httpRequest.method() == HttpMethod.GET) { + QueryStringDecoder getDecoder = new QueryStringDecoder(httpRequest.uri()); + getDecoder.parameters().entrySet().forEach(entry -> { + bodyMap.put(entry.getKey(), entry.getValue().get(0)); + }); + } else if (httpRequest.method() == HttpMethod.POST) { + decoder = new HttpPostRequestDecoder(defaultHttpDataFactory, httpRequest); + List parmList = decoder.getBodyHttpDatas(); + for (InterfaceHttpData parm : parmList) { + if (parm.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) { + Attribute data = (Attribute) parm; + bodyMap.put(data.getName(), data.getValue()); + } + } + } else { + sendError(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED); + return; + } + + metrics.summaryMetrics.recordDecodeTimeCost(System.currentTimeMillis() - bodyDecodeStart); + String requestCode = + (httpRequest.method() == HttpMethod.POST) ? StringUtils.deleteWhitespace(httpRequest.headers().get(ProtocolKey.REQUEST_CODE)) + : MapUtils.getString(bodyMap, StringUtils.lowerCase(ProtocolKey.REQUEST_CODE), ""); + + requestCommand.setHttpMethod(httpRequest.method().name()); + requestCommand.setHttpVersion(httpRequest.protocolVersion().protocolName()); + requestCommand.setRequestCode(requestCode); + + HttpCommand responseCommand = null; + + if (!ProtocolVersion.contains(protocolVersion)) { + responseCommand = requestCommand.createHttpCommandResponse(ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getErrMsg()); + sendResponse(ctx, responseCommand.httpResponse()); + return; + } + + if (StringUtils.isBlank(requestCode) + || !StringUtils.isNumeric(requestCode) + || !RequestCode.contains(Integer.valueOf(requestCode)) + || !processorTable.containsKey(Integer.valueOf(requestCode))) { + responseCommand = requestCommand.createHttpCommandResponse(ProxyRetCode.PROXY_REQUESTCODE_INVALID.getRetCode(), ProxyRetCode.PROXY_REQUESTCODE_INVALID.getErrMsg()); + sendResponse(ctx, responseCommand.httpResponse()); + return; + } + + if (!started.get()) { + responseCommand = requestCommand.createHttpCommandResponse(ProxyRetCode.PROXY_STOP.getRetCode(), ProxyRetCode.PROXY_STOP.getErrMsg()); + sendResponse(ctx, responseCommand.httpResponse()); + return; + } + + try { + requestCommand.setHeader(Header.buildHeader(requestCode, parseHTTPHeader(httpRequest))); + requestCommand.setBody(Body.buildBody(requestCode, bodyMap)); + } catch (Exception e) { + responseCommand = requestCommand.createHttpCommandResponse(ProxyRetCode.PROXY_RUNTIME_ERR.getRetCode(), ProxyRetCode.PROXY_RUNTIME_ERR.getErrMsg() + ProxyUtil.stackTrace(e, 3)); + sendResponse(ctx, responseCommand.httpResponse()); + return; + } + + if (httpLogger.isDebugEnabled()) { + httpLogger.debug("{}", requestCommand); + } + + AsyncContext asyncContext = new AsyncContext(requestCommand, responseCommand, asyncContextCompleteHandler); + processProxyRequest(ctx, asyncContext); + } catch (Exception ex) { + logger.error("AbrstractHTTPServer.HTTPHandler.channelRead0 err", ex); + } finally { + try { + decoder.destroy(); + } catch (Exception e) { + } + } + } + + public void processProxyRequest(final ChannelHandlerContext ctx, + final AsyncContext asyncContext) { + final Pair choosed = processorTable.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())); + try { + choosed.getObject2().submit(() -> { + try { + if (choosed.getObject1().rejectRequest()) { + HttpCommand responseCommand = asyncContext.getRequest().createHttpCommandResponse(ProxyRetCode.PROXY_REJECT_BY_PROCESSOR_ERROR.getRetCode(), ProxyRetCode.PROXY_REJECT_BY_PROCESSOR_ERROR.getErrMsg()); + asyncContext.onComplete(responseCommand); + if (asyncContext.isComplete()) { + if (httpLogger.isDebugEnabled()) { + httpLogger.debug("{}", asyncContext.getResponse()); + } + sendResponse(ctx, responseCommand.httpResponse()); + } + return; + } + + choosed.getObject1().processRequest(ctx, asyncContext); + if (asyncContext == null || !asyncContext.isComplete()) { + return; + } + + metrics.summaryMetrics.recordHTTPReqResTimeCost(System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); + + if (httpLogger.isDebugEnabled()) { + httpLogger.debug("{}", asyncContext.getResponse()); + } + + sendResponse(ctx, asyncContext.getResponse().httpResponse()); + } catch (Exception e) { + logger.error("process error", e); + } + }); + } catch (RejectedExecutionException re) { + HttpCommand responseCommand = asyncContext.getRequest().createHttpCommandResponse(ProxyRetCode.OVERLOAD.getRetCode(), ProxyRetCode.OVERLOAD.getErrMsg()); + asyncContext.onComplete(responseCommand); + metrics.summaryMetrics.recordHTTPDiscard(); + metrics.summaryMetrics.recordHTTPReqResTimeCost(System.currentTimeMillis() - responseCommand.getReqTime()); + try { + sendResponse(ctx, asyncContext.getResponse().httpResponse()); + } catch (Exception e) { + } + } + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + super.channelReadComplete(ctx); + ctx.flush(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + if (null != cause) cause.printStackTrace(); + if (null != ctx) ctx.close(); + } + } + + class HttpConnectionHandler extends ChannelDuplexHandler { + public AtomicInteger connections = new AtomicInteger(0); + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + super.channelRegistered(ctx); + } + + @Override + public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { + super.channelUnregistered(ctx); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + int c = connections.incrementAndGet(); + if (c > 20000) { + logger.warn("client|http|channelActive|remoteAddress={}|msg={}", remoteAddress, "too many client(20000) connect " + + "this proxy server"); + ctx.close(); + return; + } + + super.channelActive(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + connections.decrementAndGet(); + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + super.channelInactive(ctx); + } + + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + if (event.state().equals(IdleState.ALL_IDLE)) { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + logger.info("client|http|userEventTriggered|remoteAddress={}|msg={}", remoteAddress, evt.getClass() + .getName()); + ctx.close(); + } + } + + ctx.fireUserEventTriggered(evt); + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/AbstractRemotingServer.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/AbstractRemotingServer.java new file mode 100644 index 0000000000..a41b056238 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/AbstractRemotingServer.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/boot/AbstractRemotingServer.java +package cn.webank.emesher.boot; +======== +package com.webank.runtime.boot; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/boot/AbstractRemotingServer.java + +import cn.webank.eventmesh.common.ThreadUtil; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +public abstract class AbstractRemotingServer { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public EventLoopGroup bossGroup; + + public EventLoopGroup ioGroup; + + public EventLoopGroup workerGroup; + + public int port; + + private EventLoopGroup initBossGroup(String threadPrefix) { + bossGroup = new NioEventLoopGroup(1, new ThreadFactory() { + AtomicInteger count = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, threadPrefix + "-boss-" + count.incrementAndGet()); + t.setDaemon(true); + return t; + } + }); + + return bossGroup; + } + + private EventLoopGroup initIOGroup(String threadPrefix) { + ioGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors(), new ThreadFactory() { + AtomicInteger count = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, threadPrefix + "-io-" + count.incrementAndGet()); + return t; + } + }); + return ioGroup; + } + + private EventLoopGroup initWokerGroup(String threadPrefix) { + workerGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors(), new ThreadFactory() { + AtomicInteger count = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, threadPrefix + "-worker-" + count.incrementAndGet()); + return t; + } + }); + return workerGroup; + } + + public void init(String threadPrefix) throws Exception { + initBossGroup(threadPrefix); + initIOGroup(threadPrefix); + initWokerGroup(threadPrefix); + } + + public void shutdown() throws Exception { + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + logger.info("shutdown bossGroup"); + } + + ThreadUtil.randomSleep(30); + + if (ioGroup != null) { + ioGroup.shutdownGracefully(); + logger.info("shutdown ioGroup"); + } + + if (workerGroup != null) { + workerGroup.shutdownGracefully(); + logger.info("shutdown workerGroup"); + } + } + + public void start() throws Exception { + + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyHTTPServer.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyHTTPServer.java new file mode 100644 index 0000000000..a261c82b48 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyHTTPServer.java @@ -0,0 +1,273 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyHTTPServer.java +package cn.webank.emesher.boot; +======== +package com.webank.runtime.boot; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/boot/ProxyHTTPServer.java + +import cn.webank.emesher.common.ServiceState; +import cn.webank.emesher.configuration.ProxyConfiguration; +import cn.webank.emesher.core.protocol.http.consumer.ConsumerManager; +import cn.webank.emesher.core.protocol.http.processor.AdminMetricsProcessor; +import cn.webank.emesher.core.protocol.http.processor.BatchSendMessageProcessor; +import cn.webank.emesher.core.protocol.http.processor.BatchSendMessageV2Processor; +import cn.webank.emesher.core.protocol.http.processor.ReplyMessageProcessor; +import cn.webank.emesher.core.protocol.http.processor.SendAsyncMessageProcessor; +import cn.webank.emesher.core.protocol.http.processor.SendSyncMessageProcessor; +import cn.webank.emesher.core.protocol.http.processor.SubscribeProcessor; +import cn.webank.emesher.core.protocol.http.processor.UnSubscribeProcessor; +import cn.webank.emesher.core.protocol.http.producer.ProducerManager; +import cn.webank.emesher.core.protocol.http.push.AbstractHTTPPushRequest; +import cn.webank.emesher.core.protocol.http.retry.HttpRetryer; +import cn.webank.eventmesh.common.ThreadPoolFactory; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.emesher.metrics.http.HTTPMetricsServer; +import com.google.common.eventbus.EventBus; +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyHTTPServer.java +======== +import com.webank.runtime.common.ServiceState; +import com.webank.runtime.configuration.ProxyConfiguration; +import com.webank.runtime.core.protocol.http.consumer.ConsumerManager; +import com.webank.runtime.core.protocol.http.processor.*; +import com.webank.runtime.core.protocol.http.producer.ProducerManager; +import com.webank.runtime.core.protocol.http.push.AbstractHTTPPushRequest; +import com.webank.runtime.core.protocol.http.retry.HttpRetryer; +import com.webank.runtime.metrics.http.HTTPMetricsServer; +import com.webank.eventmesh.common.ThreadPoolFactory; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/boot/ProxyHTTPServer.java + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; + +public class ProxyHTTPServer extends AbrstractHTTPServer { + + private ProxyServer proxyServer; + + public ServiceState serviceState; + + private ProxyConfiguration proxyConfiguration; + + public ProxyHTTPServer(ProxyServer proxyServer, + ProxyConfiguration proxyConfiguration) { + super(proxyConfiguration.httpServerPort); + this.proxyServer = proxyServer; + this.proxyConfiguration = proxyConfiguration; + } + + public ProxyServer getProxyServer() { + return proxyServer; + } + + public EventBus eventBus = new EventBus(); + + private ConsumerManager consumerManager; + + private ProducerManager producerManager; + + private HttpRetryer httpRetryer; + + public ThreadPoolExecutor batchMsgExecutor; + + public ThreadPoolExecutor sendMsgExecutor; + + public ThreadPoolExecutor replyMsgExecutor; + + public ThreadPoolExecutor pushMsgExecutor; + + public ThreadPoolExecutor clientManageExecutor; + + public ThreadPoolExecutor rmbTraceUploader; + + public ThreadPoolExecutor adminExecutor; + + public void shutdownThreadPool() throws Exception { + batchMsgExecutor.shutdown(); + rmbTraceUploader.shutdown(); + adminExecutor.shutdown(); + clientManageExecutor.shutdown(); + sendMsgExecutor.shutdown(); + pushMsgExecutor.shutdown(); + replyMsgExecutor.shutdown(); + } + + public void initThreadPool() throws Exception { + + BlockingQueue batchMsgThreadPoolQueue = new LinkedBlockingQueue(proxyConfiguration.proxyServerBatchBlockQSize); + batchMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor(proxyConfiguration.proxyServerBatchMsgThreadNum, + proxyConfiguration.proxyServerBatchMsgThreadNum, batchMsgThreadPoolQueue, "proxy-batchmsg-", true); + + BlockingQueue sendMsgThreadPoolQueue = new LinkedBlockingQueue(proxyConfiguration.proxyServerSendMsgBlockQSize); + sendMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor(proxyConfiguration.proxyServerSendMsgThreadNum, + proxyConfiguration.proxyServerSendMsgThreadNum, sendMsgThreadPoolQueue, "proxy-sendmsg-",true); + + BlockingQueue pushMsgThreadPoolQueue = new LinkedBlockingQueue(proxyConfiguration.proxyServerPushMsgBlockQSize); + pushMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor(proxyConfiguration.proxyServerPushMsgThreadNum, + proxyConfiguration.proxyServerPushMsgThreadNum, pushMsgThreadPoolQueue, "proxy-pushmsg-",true); + + BlockingQueue clientManageThreadPoolQueue = new LinkedBlockingQueue(proxyConfiguration.proxyServerClientManageBlockQSize); + clientManageExecutor = ThreadPoolFactory.createThreadPoolExecutor(proxyConfiguration.proxyServerClientManageThreadNum, + proxyConfiguration.proxyServerClientManageThreadNum, clientManageThreadPoolQueue, "proxy-clientmanage-",true); + + BlockingQueue adminThreadPoolQueue = new LinkedBlockingQueue(50); + adminExecutor = ThreadPoolFactory.createThreadPoolExecutor(proxyConfiguration.proxyServerAdminThreadNum, + proxyConfiguration.proxyServerAdminThreadNum, adminThreadPoolQueue, "proxy-admin-",true); + + BlockingQueue rmbTraceLogThreadPoolQueue = new LinkedBlockingQueue(50); + rmbTraceUploader = ThreadPoolFactory.createThreadPoolExecutor(proxyConfiguration.proxyServerAdminThreadNum, + proxyConfiguration.proxyServerAdminThreadNum, rmbTraceLogThreadPoolQueue, "proxy-tracelog-",true); + + BlockingQueue replyMessageThreadPoolQueue = new LinkedBlockingQueue(100); + replyMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor(proxyConfiguration.proxyServerReplyMsgThreadNum, + proxyConfiguration.proxyServerReplyMsgThreadNum, replyMessageThreadPoolQueue, "proxy-replymsg-",true); + } + + public ThreadPoolExecutor getBatchMsgExecutor() { + return batchMsgExecutor; + } + + public ThreadPoolExecutor getSendMsgExecutor() { + return sendMsgExecutor; + } + + public ThreadPoolExecutor getReplyMsgExecutor() { + return replyMsgExecutor; + } + + public ThreadPoolExecutor getPushMsgExecutor() { + return pushMsgExecutor; + } + + public ThreadPoolExecutor getClientManageExecutor() { + return clientManageExecutor; + } + + public ThreadPoolExecutor getAdminExecutor() { + return adminExecutor; + } + + public void init() throws Exception { + logger.info("==================ProxyHTTPServer Initialing=================="); + super.init("proxy-http"); + + initThreadPool(); + + metrics = new HTTPMetricsServer(this); + metrics.init(); + + consumerManager = new ConsumerManager(this); + consumerManager.init(); + + producerManager = new ProducerManager(this); + producerManager.init(); + + httpRetryer = new HttpRetryer(this); + httpRetryer.init(); + + registerHTTPRequestProcessor(); + + logger.info("--------------------------ProxyHTTPServer inited"); + } + + public void start() throws Exception { + super.start(); + metrics.start(); + consumerManager.start(); + producerManager.start(); + httpRetryer.start(); + logger.info("--------------------------ProxyHTTPServer started"); + } + + public void shutdown() throws Exception { + + super.shutdown(); + + metrics.shutdown(); + + consumerManager.shutdown(); + + shutdownThreadPool(); + + AbstractHTTPPushRequest.httpClientPool.shutdown(); + + producerManager.shutdown(); + + httpRetryer.shutdown(); + logger.info("--------------------------ProxyHTTPServer shutdown"); + } + + public void registerHTTPRequestProcessor() { + BatchSendMessageProcessor batchSendMessageProcessor = new BatchSendMessageProcessor(this); + registerProcessor(RequestCode.MSG_BATCH_SEND.getRequestCode(), + batchSendMessageProcessor, batchMsgExecutor); + + BatchSendMessageV2Processor batchSendMessageV2Processor = new BatchSendMessageV2Processor(this); + registerProcessor(RequestCode.MSG_BATCH_SEND_V2.getRequestCode(), + batchSendMessageV2Processor, batchMsgExecutor); + + SendSyncMessageProcessor sendSyncMessageProcessor = new SendSyncMessageProcessor(this); + registerProcessor(RequestCode.MSG_SEND_SYNC.getRequestCode(), + sendSyncMessageProcessor, sendMsgExecutor); + + SendAsyncMessageProcessor sendAsyncMessageProcessor = new SendAsyncMessageProcessor(this); + registerProcessor(RequestCode.MSG_SEND_ASYNC.getRequestCode(), + sendAsyncMessageProcessor, sendMsgExecutor); + + AdminMetricsProcessor adminMetricsProcessor = new AdminMetricsProcessor(this); + registerProcessor(RequestCode.ADMIN_METRICS.getRequestCode(), adminMetricsProcessor, adminExecutor); + + SubscribeProcessor subscribeProcessor = new SubscribeProcessor(this); + registerProcessor(RequestCode.SUBSCRIBE.getRequestCode(), subscribeProcessor, clientManageExecutor); + + UnSubscribeProcessor unSubscribeProcessor = new UnSubscribeProcessor(this); + registerProcessor(RequestCode.UNSUBSCRIBE.getRequestCode(), unSubscribeProcessor, clientManageExecutor); + + ReplyMessageProcessor replyMessageProcessor = new ReplyMessageProcessor(this); + registerProcessor(RequestCode.REPLY_MESSAGE.getRequestCode(), replyMessageProcessor, replyMsgExecutor); + } + + public ConsumerManager getConsumerManager() { + return consumerManager; + } + + public ProducerManager getProducerManager() { + return producerManager; + } + + public ServiceState getServiceState() { + return serviceState; + } + + public ProxyConfiguration getProxyConfiguration() { + return proxyConfiguration; + } + + public EventBus getEventBus() { + return eventBus; + } + + public HttpRetryer getHttpRetryer() { + return httpRetryer; + } + + public ThreadPoolExecutor getRmbTraceUploader() { + return rmbTraceUploader; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyServer.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyServer.java new file mode 100644 index 0000000000..d28b36ceea --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyServer.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyServer.java +package cn.webank.emesher.boot; + +import cn.webank.emesher.common.ServiceState; +import cn.webank.emesher.configuration.AccessConfiguration; +import cn.webank.emesher.configuration.ProxyConfiguration; +======== +package com.webank.runtime.boot; + +import com.webank.runtime.common.ServiceState; +import com.webank.runtime.configuration.AccessConfiguration; +import com.webank.runtime.configuration.ProxyConfiguration; +import com.webank.runtime.constants.ProxyConstants; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/boot/ProxyServer.java +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProxyServer { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + public ProxyHTTPServer proxyHTTPServer; + + private ProxyTCPServer proxyTCPServer; + + private ProxyConfiguration proxyConfiguration; + + private AccessConfiguration accessConfiguration; + + private ServiceState serviceState; + + public ProxyServer(ProxyConfiguration proxyConfiguration, + AccessConfiguration accessConfiguration) { + this.proxyConfiguration = proxyConfiguration; + this.accessConfiguration = accessConfiguration; + } + + public void init() throws Exception { + proxyHTTPServer = new ProxyHTTPServer(this, proxyConfiguration); + proxyHTTPServer.init(); + proxyTCPServer = new ProxyTCPServer(this, accessConfiguration); + if (accessConfiguration.proxyTcpServerEnabled) { + proxyTCPServer.init(); + } + serviceState = ServiceState.INITED; + logger.info("server state:{}",serviceState); + } + + public void start() throws Exception { + proxyHTTPServer.start(); + if (accessConfiguration.proxyTcpServerEnabled) { + proxyTCPServer.start(); + } + serviceState = ServiceState.RUNNING; + logger.info("server state:{}",serviceState); + } + + public void shutdown() throws Exception { + serviceState = ServiceState.STOPING; + logger.info("server state:{}",serviceState); + proxyHTTPServer.shutdown(); + if (accessConfiguration.proxyTcpServerEnabled) { + proxyTCPServer.shutdown(); + } + serviceState = ServiceState.STOPED; + logger.info("server state:{}",serviceState); + } + + public ProxyHTTPServer getProxyHTTPServer() { + return proxyHTTPServer; + } + + public ProxyTCPServer getProxyTCPServer() { + return proxyTCPServer; + } + + public ServiceState getServiceState() { return serviceState; } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyStartup.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyStartup.java new file mode 100644 index 0000000000..0045b7ac93 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyStartup.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyStartup.java +package cn.webank.emesher.boot; + +import cn.webank.emesher.configuration.AccessConfiguration; +import cn.webank.emesher.configuration.ConfigurationWraper; +import cn.webank.emesher.configuration.ProxyConfiguration; +import cn.webank.emesher.constants.ProxyConstants; +======== +package com.webank.runtime.boot; + +import com.webank.runtime.configuration.AccessConfiguration; +import com.webank.runtime.configuration.ConfigurationWraper; +import com.webank.runtime.configuration.ProxyConfiguration; +import com.webank.runtime.constants.ProxyConstants; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/boot/ProxyStartup.java +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +public class ProxyStartup { + + public static Logger logger = LoggerFactory.getLogger(ProxyStartup.class); + + public static void main(String[] args) throws Exception { + try{ + ConfigurationWraper configurationWraper = + new ConfigurationWraper(ProxyConstants.PROXY_CONF_HOME + + File.separator + + ProxyConstants.PROXY_CONF_FILE, false); + ProxyConfiguration proxyConfiguration = new ProxyConfiguration(configurationWraper); + proxyConfiguration.init(); + AccessConfiguration accessConfiguration = new AccessConfiguration(configurationWraper); + accessConfiguration.init(); + ProxyServer server = new ProxyServer(proxyConfiguration, accessConfiguration); + server.init(); + server.start(); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + logger.info("proxy shutting down hook begin..."); + long start = System.currentTimeMillis(); + server.shutdown(); + long end = System.currentTimeMillis(); + logger.info("proxy shutdown cost {}ms", end - start); + } catch (Exception e) { + logger.error("exception when shutdown...", e); + } + })); + }catch (Throwable e){ + logger.error("Proxy start fail.", e); + e.printStackTrace(); +// System.exit(1); + } + + } +} + diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyTCPServer.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyTCPServer.java new file mode 100644 index 0000000000..fb60c5b2f4 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyTCPServer.java @@ -0,0 +1,296 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyTCPServer.java +package cn.webank.emesher.boot; +======== +package com.webank.runtime.boot; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/boot/ProxyTCPServer.java + +import cn.webank.eventmesh.common.protocol.tcp.codec.Codec; +import cn.webank.emesher.admin.controller.ClientManageController; +import cn.webank.emesher.configuration.AccessConfiguration; +import cn.webank.emesher.core.protocol.tcp.client.ProxyTcpConnectionHandler; +import cn.webank.emesher.core.protocol.tcp.client.ProxyTcpExceptionHandler; +import cn.webank.emesher.core.protocol.tcp.client.ProxyTcpMessageDispatcher; +import cn.webank.emesher.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import cn.webank.emesher.core.protocol.tcp.client.session.push.retry.ProxyTcpRetryer; +import cn.webank.eventmesh.common.ThreadPoolFactory; +import cn.webank.emesher.metrics.tcp.ProxyTcpMonitor; +import cn.webank.emesher.threads.ProxyThreadFactoryImpl; +import cn.webank.emesher.threads.ThreadPoolHelper; +import com.google.common.util.concurrent.RateLimiter; +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/boot/ProxyTCPServer.java +======== +import com.webank.runtime.admin.controller.ClientManageController; +import com.webank.runtime.configuration.AccessConfiguration; +import com.webank.runtime.core.protocol.tcp.client.ProxyTcpConnectionHandler; +import com.webank.runtime.core.protocol.tcp.client.ProxyTcpExceptionHandler; +import com.webank.runtime.core.protocol.tcp.client.ProxyTcpMessageDispatcher; +import com.webank.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import com.webank.runtime.core.protocol.tcp.client.session.push.retry.ProxyTcpRetryer; +import com.webank.runtime.metrics.tcp.ProxyTcpMonitor; +import com.webank.runtime.util.ProxyThreadFactoryImpl; +import com.webank.eventmesh.common.ThreadPoolFactory; +import com.webank.eventmesh.common.protocol.tcp.codec.Codec; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/boot/ProxyTCPServer.java +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.channel.AdaptiveRecvByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.timeout.IdleStateHandler; +import io.netty.handler.traffic.ChannelTrafficShapingHandler; +import io.netty.handler.traffic.GlobalTrafficShapingHandler; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; + +public class ProxyTCPServer extends AbstractRemotingServer { + + private ClientSessionGroupMapping clientSessionGroupMapping; + + private ProxyTcpRetryer proxyTcpRetryer; + + private ProxyTcpMonitor proxyTcpMonitor; + + private ClientManageController clientManageController; + + private ProxyServer proxyServer; + + private AccessConfiguration accessConfiguration; + + private GlobalTrafficShapingHandler globalTrafficShapingHandler; + + public static ScheduledExecutorService scheduler; + + public static ExecutorService traceLogExecutor; + + public static ScheduledExecutorService configCenterUpdateScheduler; + + public static ExecutorService taskHandleExecutorService; + + public ScheduledFuture tcpRegisterTask; + + public RateLimiter rateLimiter; + + public ProxyTCPServer(ProxyServer proxyServer, + AccessConfiguration accessConfiguration) { + super(); + this.proxyServer = proxyServer; + this.accessConfiguration = accessConfiguration; + } + + private void startServer() throws Exception { + Runnable r = () -> { + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group(bossGroup, ioGroup) + .channel(NioServerSocketChannel.class) + .option(ChannelOption.SO_BACKLOG, 128) + .option(ChannelOption.TCP_NODELAY, true) + .option(ChannelOption.SO_REUSEADDR, true) + .option(ChannelOption.SO_KEEPALIVE, false) + .option(ChannelOption.SO_TIMEOUT, 600000) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000) + .option(ChannelOption.SO_LINGER, 0) + .childOption(ChannelOption.SO_SNDBUF, 65535 * 4) + .childOption(ChannelOption.SO_RCVBUF, 65535 * 4) + .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(2048, 4096, 65536)) + .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) + .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(Channel ch) throws Exception { + ch.pipeline().addLast(new Codec.Encoder()) + .addLast(new Codec.Decoder()) + .addLast("global-traffic-shaping", globalTrafficShapingHandler) + .addLast("channel-traffic-shaping", newCTSHandler()) + .addLast(new ProxyTcpConnectionHandler(ProxyTCPServer.this)) + .addLast(workerGroup, new IdleStateHandler(accessConfiguration.proxyTcpIdleReadSeconds, + accessConfiguration.proxyTcpIdleWriteSeconds, + accessConfiguration.proxyTcpIdleAllSeconds), + new ProxyTcpMessageDispatcher(ProxyTCPServer.this), + new ProxyTcpExceptionHandler(ProxyTCPServer.this) + ); + } + }); + try { + int port = accessConfiguration.proxyTcpServerPort; + ChannelFuture f = bootstrap.bind(port).sync(); + logger.info("ProxyTCPServer[port={}] started.....", port); + f.channel().closeFuture().sync(); + } catch (Exception e) { + logger.error("ProxyTCPServer RemotingServer Start Err!", e); + try { + shutdown(); + } catch (Exception e1) { + logger.error("ProxyTCPServer RemotingServer shutdown Err!", e); + } + return; + } + }; + + Thread t = new Thread(r, "proxy-tcp-server"); + t.start(); + } + + public void init() throws Exception { + logger.info("==================ProxyTCPServer Initialing=================="); + initThreadPool(); + + rateLimiter = RateLimiter.create(accessConfiguration.proxyTcpMsgReqnumPerSecond); + + globalTrafficShapingHandler = newGTSHandler(); + + clientManageController = new ClientManageController(this); + + clientSessionGroupMapping = new ClientSessionGroupMapping(this); + clientSessionGroupMapping.init(); + + proxyTcpRetryer = new ProxyTcpRetryer(this); + proxyTcpRetryer.init(); + + proxyTcpMonitor = new ProxyTcpMonitor(this); + proxyTcpMonitor.init(); + + logger.info("--------------------------ProxyTCPServer Inited"); + } + + public void start() throws Exception { + startServer(); + + clientSessionGroupMapping.start(); + + proxyTcpRetryer.start(); + + proxyTcpMonitor.start(); + + clientManageController.start(); + + logger.info("--------------------------ProxyTCPServer Started"); + } + + public void shutdown() throws Exception { + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + logger.info("shutdown bossGroup, no client is allowed to connect access server"); + } + + clientSessionGroupMapping.shutdown(); + try { + Thread.sleep(40 * 1000); + } catch (InterruptedException e) { + logger.error("interruptedException occurred while sleeping", e); + } + + globalTrafficShapingHandler.release(); + + if (ioGroup != null) { + ioGroup.shutdownGracefully(); + logger.info("shutdown ioGroup"); + } + if (workerGroup != null) { + workerGroup.shutdownGracefully(); + logger.info("shutdown workerGroup"); + } + + proxyTcpRetryer.shutdown(); + + proxyTcpMonitor.shutdown(); + + shutdownThreadPool(); + logger.info("--------------------------ProxyTCPServer Shutdown"); + } + + private void initThreadPool() throws Exception { + super.init("proxy-tcp"); + + scheduler = ThreadPoolFactory.createScheduledExecutor(accessConfiguration.proxyTcpGlobalScheduler, new ProxyThreadFactoryImpl("proxy-tcp-scheduler", true)); + + traceLogExecutor = ThreadPoolFactory.createThreadPoolExecutor(accessConfiguration.proxyTcpTraceLogExecutorPoolSize, accessConfiguration.proxyTcpTraceLogExecutorPoolSize, new LinkedBlockingQueue(10000), new ProxyThreadFactoryImpl("proxy-tcp-trace", true)); + + configCenterUpdateScheduler = ThreadPoolFactory.createScheduledExecutor(accessConfiguration.proxyTcpCcUpdateExecutorPoolSize, new ProxyThreadFactoryImpl("proxy-tcp-cc-update",true)); + + taskHandleExecutorService = ThreadPoolFactory.createThreadPoolExecutor(accessConfiguration.proxyTcpTaskHandleExecutorPoolSize, accessConfiguration.proxyTcpTaskHandleExecutorPoolSize, new LinkedBlockingQueue(10000), new ProxyThreadFactoryImpl("proxy-tcp-task-handle", true));; + } + + private void shutdownThreadPool(){ + traceLogExecutor.shutdown(); + configCenterUpdateScheduler.shutdown(); + scheduler.shutdown(); + taskHandleExecutorService.shutdown(); + + ThreadPoolHelper.shutdownNettyClientSelector(); + ThreadPoolHelper.shutdownNettyClientWorkerThread(); + ThreadPoolHelper.shutdownMQClientInstanceExecutorService(); + ThreadPoolHelper.shutdownSharedScheduledExecutorService(); + ThreadPoolHelper.shutdownRebalanceImplExecutorService(); + ThreadPoolHelper.shutdownRebalanceServiceExecutorService(); + ThreadPoolHelper.shutdownPullMessageServiceExecutorService(); + ThreadPoolHelper.shutdownPullMessageRetryServiceExecutorService(); + ThreadPoolHelper.shutdownExecutorService(); + ThreadPoolHelper.shutdownConsumeMessageExecutor(); + ThreadPoolHelper.shutdownProducerCheckExecutorService(); + } + + private GlobalTrafficShapingHandler newGTSHandler() { + GlobalTrafficShapingHandler handler = new GlobalTrafficShapingHandler(scheduler, 0, accessConfiguration.getGtc().getReadLimit()) { + @Override + protected long calculateSize(Object msg) { + return 1; + } + }; + handler.setMaxTimeWait(1000); + return handler; + } + + private ChannelTrafficShapingHandler newCTSHandler() { + ChannelTrafficShapingHandler handler = new ChannelTrafficShapingHandler(0, accessConfiguration.getCtc().getReadLimit()) { + @Override + protected long calculateSize(Object msg) { + return 1; + } + }; + handler.setMaxTimeWait(3000); + return handler; + } + + public ClientSessionGroupMapping getClientSessionGroupMapping() { + return clientSessionGroupMapping; + } + + public ProxyTcpRetryer getProxyTcpRetryer() { + return proxyTcpRetryer; + } + + public ProxyTcpMonitor getProxyTcpMonitor() { + return proxyTcpMonitor; + } + + public ProxyServer getProxyServer() { + return proxyServer; + } + + public AccessConfiguration getAccessConfiguration() { + return accessConfiguration; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/common/Pair.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/common/Pair.java new file mode 100644 index 0000000000..30b0acce06 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/common/Pair.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/common/Pair.java +package cn.webank.emesher.common; +======== +package com.webank.runtime.common; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/common/Pair.java + +public class Pair { + private T1 object1; + private T2 object2; + + public Pair(T1 object1, T2 object2) { + this.object1 = object1; + this.object2 = object2; + } + + public T1 getObject1() { + return object1; + } + + public void setObject1(T1 object1) { + this.object1 = object1; + } + + public T2 getObject2() { + return object2; + } + + public void setObject2(T2 object2) { + this.object2 = object2; + } +} + diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/common/ServiceState.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/common/ServiceState.java new file mode 100644 index 0000000000..c6988f2ea3 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/common/ServiceState.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/common/ServiceState.java +package cn.webank.emesher.common; +======== +package com.webank.runtime.common; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/common/ServiceState.java + +public enum ServiceState { + + INITED, + + RUNNING, + + STOPING, + + STOPED; +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/AccessConfiguration.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/AccessConfiguration.java new file mode 100644 index 0000000000..d79c6fb39c --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/AccessConfiguration.java @@ -0,0 +1,334 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/AccessConfiguration.java +package cn.webank.emesher.configuration; +======== +package com.webank.runtime.configuration; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/configuration/AccessConfiguration.java + +import com.google.common.base.Preconditions; +import org.apache.commons.lang3.StringUtils; + +public class EventMeshConfiguration extends CommonConfiguration { + public int proxyTcpServerPort = 10000; + + public int proxyTcpIdleAllSeconds = 60; + + public int proxyTcpIdleWriteSeconds = 60; + + public int proxyTcpIdleReadSeconds = 60; + + public Integer proxyTcpMsgReqnumPerSecond = 15000; + + /** + * TCP Server allows max client num + */ + public int proxyTcpClientMaxNum = 10000; + + //======================================= New add config ================================= + /** + * whether enable TCP Serer + */ + public boolean proxyTcpServerEnabled = Boolean.FALSE; + + public int proxyTcpGlobalScheduler = 5; + + public int proxyTcpTraceLogExecutorPoolSize = 5; + + public int proxyTcpCcUpdateExecutorPoolSize = 2; + + public int proxyTcpTaskHandleExecutorPoolSize = Runtime.getRuntime().availableProcessors(); + + public int proxyTcpSessionExpiredInMills = 60000; + + public int proxyTcpSessionUpstreamBufferSize = 100; + + public int proxyTcpSessionDownstreamUnackSize = 12; + + public int proxyTcpMsgRetryTimes = 3; + + public int proxyTcpMsgRetryDelayInMills = 500; + + public int proxyTcpMsgRetryQueueSize = 10000; + + public Integer proxyTcpRebalanceIntervalInMills = 30 * 1000; + + public int proxyServerAdminPort = 10106; + + public boolean proxyTcpSendBackEnabled = Boolean.TRUE; + + public int proxyTcpSendBackMaxTimes = 3; + + public int proxyTcpPushFailIsolateTimeInMills = 30 * 1000; + + public int proxyTcpDownStreamMapSize = 500; + + private TrafficShapingConfig gtc = new TrafficShapingConfig(0, 10_000, 1_000, 2000); + private TrafficShapingConfig ctc = new TrafficShapingConfig(0, 2_000, 1_000, 10_000); + + public EventMeshConfiguration(ConfigurationWraper configurationWraper){ + super(configurationWraper); + } + + public void init(){ + super.init(); + String proxyTcpServerPortStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_TCP_PORT); + Preconditions.checkState(StringUtils.isNotEmpty(proxyTcpServerPortStr) && StringUtils.isNumeric(proxyTcpServerPortStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_TCP_PORT)); + proxyTcpServerPort = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpServerPortStr)); + + String proxyTcpIdleReadSecondsStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_READER_IDLE_SECONDS); + Preconditions.checkState(StringUtils.isNotEmpty(proxyTcpIdleReadSecondsStr) && StringUtils.isNumeric(proxyTcpIdleReadSecondsStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_READER_IDLE_SECONDS)); + proxyTcpIdleReadSeconds = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpIdleReadSecondsStr)); + + String proxyTcpIdleWriteSecondsStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_WRITER_IDLE_SECONDS); + Preconditions.checkState(StringUtils.isNotEmpty(proxyTcpIdleWriteSecondsStr) && StringUtils.isNumeric(proxyTcpIdleWriteSecondsStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_WRITER_IDLE_SECONDS)); + proxyTcpIdleWriteSeconds = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpIdleWriteSecondsStr)); + + String proxyTcpIdleAllSecondsStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_ALL_IDLE_SECONDS); + Preconditions.checkState(StringUtils.isNotEmpty(proxyTcpIdleAllSecondsStr) && StringUtils.isNumeric(proxyTcpIdleAllSecondsStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_ALL_IDLE_SECONDS)); + proxyTcpIdleAllSeconds = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpIdleAllSecondsStr)); + + String proxyTcpMsgReqnumPerSecondStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_MSG_REQ_NUM_PER_SECONDS); + Preconditions.checkState(StringUtils.isNotEmpty(proxyTcpMsgReqnumPerSecondStr) && StringUtils.isNumeric(proxyTcpMsgReqnumPerSecondStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_MSG_REQ_NUM_PER_SECONDS)); + proxyTcpMsgReqnumPerSecond = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpMsgReqnumPerSecondStr)); + + String proxyTcpClientMaxNumStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_CLIENT_MAX_NUM); + Preconditions.checkState(StringUtils.isNotEmpty(proxyTcpClientMaxNumStr) && StringUtils.isNumeric(proxyTcpClientMaxNumStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_CLIENT_MAX_NUM)); + proxyTcpClientMaxNum = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpClientMaxNumStr)); + + String proxyTcpServerEnabledStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_TCP_SERVER_ENABLED); + if (StringUtils.isNotEmpty(proxyTcpServerEnabledStr)) { + proxyTcpServerEnabled = Boolean.valueOf(StringUtils.deleteWhitespace(proxyTcpServerEnabledStr)); + } + + String proxyTcpGlobalSchedulerStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_GLOBAL_SCHEDULER); + if(StringUtils.isNotEmpty(proxyTcpGlobalSchedulerStr)){ + Preconditions.checkState(StringUtils.isNumeric(proxyTcpGlobalSchedulerStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_GLOBAL_SCHEDULER)); + proxyTcpGlobalScheduler = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpGlobalSchedulerStr)); + } + + String proxyTcpTraceLogExecutorPoolSizeStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_TCP_TRACE_LOG_POOL_SIZE); + if(StringUtils.isNotEmpty(proxyTcpTraceLogExecutorPoolSizeStr)){ + Preconditions.checkState(StringUtils.isNumeric(proxyTcpTraceLogExecutorPoolSizeStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_TCP_TRACE_LOG_POOL_SIZE)); + proxyTcpTraceLogExecutorPoolSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpTraceLogExecutorPoolSizeStr)); + } + + String proxyTcpCcUpdateExecutorPoolSizeStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_TCP_CC_UPDATE_POOL_SIZE); + if(StringUtils.isNotEmpty(proxyTcpCcUpdateExecutorPoolSizeStr)){ + Preconditions.checkState(StringUtils.isNumeric(proxyTcpCcUpdateExecutorPoolSizeStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_TCP_CC_UPDATE_POOL_SIZE)); + proxyTcpCcUpdateExecutorPoolSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpCcUpdateExecutorPoolSizeStr)); + } + + String proxyTcpTaskHandleExecutorPoolSizeStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_TCP_TASK_HANDLE_POOL_SIZE); + if(StringUtils.isNotEmpty(proxyTcpTaskHandleExecutorPoolSizeStr)){ + Preconditions.checkState(StringUtils.isNumeric(proxyTcpTaskHandleExecutorPoolSizeStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_TCP_TASK_HANDLE_POOL_SIZE)); + proxyTcpTaskHandleExecutorPoolSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpTaskHandleExecutorPoolSizeStr)); + } + + String proxyTcpSessionExpiredInMillsStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_SESSION_EXPIRED_TIME); + if(StringUtils.isNotEmpty(proxyTcpSessionExpiredInMillsStr)){ + Preconditions.checkState(StringUtils.isNumeric(proxyTcpSessionExpiredInMillsStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_SESSION_EXPIRED_TIME)); + proxyTcpSessionExpiredInMills = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpSessionExpiredInMillsStr)); + } + + String proxyTcpSessionUpstreamBufferSizeStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_SESSION_UPSTREAM_BUFFER_SIZE); + if(StringUtils.isNotEmpty(proxyTcpSessionUpstreamBufferSizeStr)){ + Preconditions.checkState(StringUtils.isNumeric(proxyTcpSessionUpstreamBufferSizeStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_SESSION_UPSTREAM_BUFFER_SIZE)); + proxyTcpSessionUpstreamBufferSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpSessionUpstreamBufferSizeStr)); + } + + String proxyTcpSessionDownstreamUnackSizeStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_SESSION_DOWNSTREAM_UNACK_SIZE); + if(StringUtils.isNotEmpty(proxyTcpSessionDownstreamUnackSizeStr)){ + Preconditions.checkState(StringUtils.isNumeric(proxyTcpSessionDownstreamUnackSizeStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_SESSION_DOWNSTREAM_UNACK_SIZE)); + proxyTcpSessionDownstreamUnackSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpSessionDownstreamUnackSizeStr)); + } + + //========================================proxy retry config=============================================// + String proxyTcpMsgRetryTimesStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_RETRY_PUSH_RETRY_TIMES); + if(StringUtils.isNotEmpty(proxyTcpMsgRetryTimesStr)) { + Preconditions.checkState(StringUtils.isNumeric(proxyTcpMsgRetryTimesStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_RETRY_PUSH_RETRY_TIMES)); + proxyTcpMsgRetryTimes = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpMsgRetryTimesStr)); + } + + String proxyTcpMsgRetryDelayInMillsStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_RETRY_PUSH_RETRY_DELAY); + if(StringUtils.isNotEmpty(proxyTcpMsgRetryDelayInMillsStr)) { + Preconditions.checkState(StringUtils.isNumeric(proxyTcpMsgRetryDelayInMillsStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_RETRY_PUSH_RETRY_DELAY)); + proxyTcpMsgRetryDelayInMills = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpMsgRetryDelayInMillsStr)); + } + + String proxyTcpMsgRetryQueueSizeStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_RETRY_PUSH_RETRY_QUEUE_SIZE); + if(StringUtils.isNotEmpty(proxyTcpMsgRetryQueueSizeStr)) { + Preconditions.checkState(StringUtils.isNumeric(proxyTcpMsgRetryQueueSizeStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_RETRY_PUSH_RETRY_QUEUE_SIZE)); + proxyTcpMsgRetryQueueSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpMsgRetryQueueSizeStr)); + } + +// String proxyTcpMonitorImsInterfaceStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_MONITOR_IMS_INTERFACE); +// Preconditions.checkState(StringUtils.isNotEmpty(proxyTcpMonitorImsInterfaceStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_MONITOR_IMS_INTERFACE)); +// proxyTcpMonitorImsInterface = StringUtils.trim(proxyTcpMonitorImsInterfaceStr); +// +// String accessMonitorImsEnabledStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_MONITOR_IMS_ENABLED); +// if (StringUtils.isNotEmpty(accessMonitorImsEnabledStr)) { +// proxyTcpMonitorImsEnabled = Boolean.valueOf(StringUtils.deleteWhitespace(accessMonitorImsEnabledStr)); +// } + + String proxyTcpRebalanceIntervalStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_TCP_REBALANCE_INTERVAL); + if (StringUtils.isNotEmpty(proxyTcpRebalanceIntervalStr)) { + Preconditions.checkState(StringUtils.isNumeric(proxyTcpRebalanceIntervalStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_TCP_REBALANCE_INTERVAL)); + proxyTcpRebalanceIntervalInMills = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpRebalanceIntervalStr)); + } + + String proxyServerAdminPortStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_ADMIN_HTTP_PORT); + if(StringUtils.isNotEmpty(proxyServerAdminPortStr)){ + Preconditions.checkState(StringUtils.isNumeric(proxyServerAdminPortStr), + String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_ADMIN_HTTP_PORT)); + proxyServerAdminPort = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerAdminPortStr)); + } + + String proxyTcpSendBackEnabledStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_TCP_SEND_BACK_ENABLED); + if (StringUtils.isNotEmpty(proxyTcpSendBackEnabledStr)) { + proxyTcpSendBackEnabled = Boolean.valueOf(StringUtils.deleteWhitespace(proxyTcpSendBackEnabledStr)); + } + +// String proxyTcpSendBackMaxTimesStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_TCP_SEND_BACK_MAX_TIMES); +// Preconditions.checkState(StringUtils.isNotEmpty(proxyTcpSendBackMaxTimesStr) && StringUtils.isNumeric(proxyTcpSendBackMaxTimesStr), String.format("%s error", ConfKeys.KEYS_PROXY_TCP_SEND_BACK_MAX_TIMES)); +// proxyTcpSendBackMaxTimes = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpSendBackMaxTimesStr)); + + String proxyTcpPushFailIsolateTimeInMillsStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_PUSH_FAIL_ISOLATE_TIME); + if(StringUtils.isNotEmpty(proxyTcpPushFailIsolateTimeInMillsStr)) { + Preconditions.checkState(StringUtils.isNumeric(proxyTcpPushFailIsolateTimeInMillsStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_PUSH_FAIL_ISOLATE_TIME)); + proxyTcpPushFailIsolateTimeInMills = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpPushFailIsolateTimeInMillsStr)); + } + + String proxyTcpDownStreamMapSizeStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_TCP_DOWNSTREAM_MAP_SIZE); + if(StringUtils.isNotEmpty(proxyTcpDownStreamMapSizeStr)) { + Preconditions.checkState(StringUtils.isNumeric(proxyTcpDownStreamMapSizeStr), String.format("%s error", ConfKeys.KEYS_PROXY_TCP_DOWNSTREAM_MAP_SIZE)); + proxyTcpDownStreamMapSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyTcpDownStreamMapSizeStr)); + } + } + + public TrafficShapingConfig getGtc() { + return gtc; + } + + public TrafficShapingConfig getCtc() { + return ctc; + } + + static class ConfKeys{ + + public static String KEYS_PROXY_SERVER_TCP_PORT = "proxy.server.tcp.port"; + public static String KEYS_PROXY_SERVER_READER_IDLE_SECONDS = "proxy.server.tcp.readerIdleSeconds"; + public static String KEYS_PROXY_SERVER_WRITER_IDLE_SECONDS = "proxy.server.tcp.writerIdleSeconds"; + public static String KEYS_PROXY_SERVER_ALL_IDLE_SECONDS = "proxy.server.tcp.allIdleSeconds"; + public static String KEYS_PROXY_SERVER_CLIENT_MAX_NUM = "proxy.server.tcp.clientMaxNum"; + public static String KEYS_PROXY_SERVER_MSG_REQ_NUM_PER_SECONDS = "proxy.server.tcp.msgReqnumPerSecond"; + public static String KEYS_PROXY_SERVER_TCP_REBALANCE_INTERVAL = "proxy.server.tcp.RebalanceIntervalInMills"; + public static String KEYS_PROXY_SERVER_GLOBAL_SCHEDULER = "proxy.server.global.scheduler"; + public static String KEYS_PROXY_SERVER_GLOBAL_ASYNC = "proxy.server.global.async"; + public static String KEYS_PROXY_SERVER_TCP_TRACE_LOG_POOL_SIZE = "proxy.server.tcp.traceLogExecutorPoolSize"; + public static String KEYS_PROXY_SERVER_TCP_CC_UPDATE_POOL_SIZE = "proxy.server.tcp.ccUpdateExecutorPoolSize"; + public static String KEYS_PROXY_SERVER_TCP_TASK_HANDLE_POOL_SIZE = "proxy.server.tcp.taskHandleExecutorPoolSize"; + public static String KEYS_PROXY_SERVER_SESSION_EXPIRED_TIME = "proxy.server.session.expiredInMills"; + public static String KEYS_PROXY_SERVER_SESSION_UPSTREAM_BUFFER_SIZE = "proxy.server.session.upstreamBufferSize"; + public static String KEYS_PROXY_SERVER_SESSION_DOWNSTREAM_UNACK_SIZE = "proxy.server.session.downstreamUnackSize"; + public static String KEYS_PROXY_SERVER_RETRY_PUSH_RETRY_TIMES = "proxy.server.retry.pushRetryTimes"; + public static String KEYS_PROXY_SERVER_RETRY_PUSH_RETRY_DELAY = "proxy.server.retry.pushRetryDelayInMills"; + public static String KEYS_PROXY_SERVER_RETRY_PUSH_RETRY_QUEUE_SIZE = "proxy.server.retry.pushRetryQueueSize"; + public static String KEYS_PROXY_SERVER_MONITOR_IMS_INTERFACE = "proxy.server.monitor.imsInterfaceName"; + public static String KEYS_PROXY_SERVER_MONITOR_IMS_ENABLED = "proxy.server.monitor.imsEnabled"; + public static String KEYS_PROXY_SERVER_ADMIN_HTTP_PORT = "proxy.server.admin.http.port"; + public static String KEYS_PROXY_TCP_SERVER_ENABLED = "proxy.server.tcp.enabled"; + public static String KEYS_PROXY_TCP_SEND_BACK_ENABLED = "proxy.server.tcp.sendBack.enabled"; + public static String KEYS_PROXY_TCP_SEND_BACK_MAX_TIMES = "proxy.server.tcp.sendBack.maxTimes"; + public static String KEYS_PROXY_SERVER_PUSH_FAIL_ISOLATE_TIME = "proxy.server.tcp.pushFailIsolateTimeInMills"; + public static String KEYS_PROXY_TCP_DOWNSTREAM_MAP_SIZE = "proxy.server.tcp.downstreamMapSize"; + } + + public static class TrafficShapingConfig { + long writeLimit = 0; + long readLimit = 1000; + long checkInterval = 1000; + long maxTime = 5000; + + public TrafficShapingConfig(long writeLimit, long readLimit, long checkInterval, long maxTime) { + this.writeLimit = writeLimit; + this.readLimit = readLimit; + this.checkInterval = checkInterval; + this.maxTime = maxTime; + } + + public TrafficShapingConfig() { + + } + + public long getWriteLimit() { + return writeLimit; + } + + public void setWriteLimit(long writeLimit) { + this.writeLimit = writeLimit; + } + + public long getReadLimit() { + return readLimit; + } + + public void setReadLimit(long readLimit) { + this.readLimit = readLimit; + } + + public long getCheckInterval() { + return checkInterval; + } + + public void setCheckInterval(long checkInterval) { + this.checkInterval = checkInterval; + } + + public long getMaxTime() { + return maxTime; + } + + public void setMaxTime(long maxTime) { + this.maxTime = maxTime; + } + + @Override + public String toString() { + return "TrafficShapingConfig{" + + "writeLimit=" + writeLimit + + ", readLimit=" + readLimit + + ", checkInterval=" + checkInterval + + ", maxTime=" + maxTime + + '}'; + } + } + +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/CommonConfiguration.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/CommonConfiguration.java new file mode 100644 index 0000000000..c00ae8aa2a --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/CommonConfiguration.java @@ -0,0 +1,232 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/CommonConfiguration.java +package cn.webank.emesher.configuration; + +import com.google.common.base.Preconditions; +======== +package com.webank.runtime.configuration; + +import com.google.common.base.Preconditions; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/configuration/CommonConfiguration.java +import org.apache.commons.lang3.StringUtils; + +public class CommonConfiguration { + public String proxyEnv = "P"; + public String proxyRegion = ""; + public String proxyIDC = "FT"; + public String proxyDCN = "1C0"; + public String proxyCluster = "LS"; + public String proxyName = ""; + public String sysID = "5477"; + + + public String configCenterAddr = ""; + public String namesrvAddr = ""; + public String clientUserName = "username"; + public String clientPass = "user@123"; + public Integer consumeThreadMin = 2; + public Integer consumeThreadMax = 2; + public Integer consumeQueueSize = 10000; + public Integer pullBatchSize = 32; + public Integer ackWindow = 1000; + public Integer pubWindow = 100; + public long consumeTimeout = 0L; + public Integer pollNameServerInteval = 10 * 1000; + public Integer heartbeatBrokerInterval = 30 * 1000; + public Integer rebalanceInterval = 20 * 1000; + public Integer proxyRegisterIntervalInMills = 10 * 1000; + public Integer proxyFetchRegistryAddrInterval = 10 * 1000; + protected ConfigurationWraper configurationWraper; + + public CommonConfiguration(ConfigurationWraper configurationWraper) { + this.configurationWraper = configurationWraper; + } + + public void init() { + String proxyEnvStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_ENV); + Preconditions.checkState(StringUtils.isNotEmpty(proxyEnvStr), String.format("%s error", ConfKeys.KEYS_PROXY_ENV)); + proxyEnv = StringUtils.deleteWhitespace(proxyEnvStr); + + String proxyRegionStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_REGION); + Preconditions.checkState(StringUtils.isNotEmpty(proxyRegionStr), String.format("%s error", ConfKeys.KEYS_PROXY_REGION)); + proxyRegion = StringUtils.deleteWhitespace(proxyRegionStr); + + String sysIdStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SYSID); + Preconditions.checkState(StringUtils.isNotEmpty(sysIdStr) && StringUtils.isNumeric(sysIdStr), String.format("%s error", ConfKeys.KEYS_PROXY_SYSID)); + sysID = StringUtils.deleteWhitespace(sysIdStr); + + String proxyClusterStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_CLUSTER); + Preconditions.checkState(StringUtils.isNotEmpty(proxyClusterStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_CLUSTER)); + proxyCluster = StringUtils.deleteWhitespace(proxyClusterStr); + + String proxyNameStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_NAME); + Preconditions.checkState(StringUtils.isNotEmpty(proxyNameStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_NAME)); + proxyName = StringUtils.deleteWhitespace(proxyNameStr); + + String proxyIDCStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_IDC); + Preconditions.checkState(StringUtils.isNotEmpty(proxyIDCStr), String.format("%s error", ConfKeys.KEYS_PROXY_IDC)); + proxyIDC = StringUtils.deleteWhitespace(proxyIDCStr); + + String proxyDCNStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DCN); + Preconditions.checkState(StringUtils.isNotEmpty(proxyDCNStr), String.format("%s error", ConfKeys.KEYS_PROXY_DCN)); + proxyDCN = StringUtils.deleteWhitespace(proxyDCNStr); + + String clientUserNameStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_USERNAME); + if (StringUtils.isNotBlank(clientUserNameStr)) { + clientUserName = StringUtils.trim(clientUserNameStr); + } + + String clientPassStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_PASSWORD); + if (StringUtils.isNotBlank(clientPassStr)) { + clientPass = StringUtils.trim(clientPassStr); + } + + String proxyConfigCenterAddrStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CONFIGCENTER); + Preconditions.checkState(StringUtils.isNotEmpty(proxyConfigCenterAddrStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CONFIGCENTER)); + configCenterAddr = StringUtils.trim(proxyConfigCenterAddrStr); + + String namesrvAddrStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_NAMESRV_ADDR); + Preconditions.checkState(StringUtils.isNotEmpty(proxyConfigCenterAddrStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_NAMESRV_ADDR)); + namesrvAddr = StringUtils.trim(namesrvAddrStr); + + String consumeThreadPoolMinStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CONSUME_THREADPOOL_MIN); + if(StringUtils.isNotEmpty(consumeThreadPoolMinStr)){ + Preconditions.checkState(StringUtils.isNumeric(consumeThreadPoolMinStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CONSUME_THREADPOOL_MIN)); + consumeThreadMin = Integer.valueOf(consumeThreadPoolMinStr); + } + + String consumeThreadPoolMaxStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CONSUME_THREADPOOL_MAX); + if(StringUtils.isNotEmpty(consumeThreadPoolMaxStr)){ + Preconditions.checkState(StringUtils.isNumeric(consumeThreadPoolMaxStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CONSUME_THREADPOOL_MAX)); + consumeThreadMax = Integer.valueOf(consumeThreadPoolMaxStr); + } + + String consumerThreadPoolQueueSizeStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CONSUME_THREADPOOL_QUEUESIZE); + if(StringUtils.isNotEmpty(consumerThreadPoolQueueSizeStr)){ + Preconditions.checkState(StringUtils.isNumeric(consumerThreadPoolQueueSizeStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CONSUME_THREADPOOL_QUEUESIZE)); + consumeQueueSize = Integer.valueOf(consumerThreadPoolQueueSizeStr); + } + + String clientAckWindowStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_ACK_WINDOW); + if(StringUtils.isNotEmpty(clientAckWindowStr)){ + Preconditions.checkState(StringUtils.isNumeric(clientAckWindowStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_ACK_WINDOW)); + ackWindow = Integer.valueOf(clientAckWindowStr); + } + + String clientPubWindowStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_PUB_WINDOW); + if(StringUtils.isNotEmpty(clientPubWindowStr)){ + Preconditions.checkState(StringUtils.isNumeric(clientPubWindowStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_PUB_WINDOW)); + pubWindow = Integer.valueOf(clientPubWindowStr); + } + + String consumeTimeoutStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_CONSUME_TIMEOUT); + if(StringUtils.isNotBlank(consumeTimeoutStr)) { + Preconditions.checkState(StringUtils.isNumeric(consumeTimeoutStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_CONSUME_TIMEOUT)); + consumeTimeout = Long.valueOf(consumeTimeoutStr); + } + + String clientPullBatchSizeStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_PULL_BATCHSIZE); + if(StringUtils.isNotEmpty(clientPullBatchSizeStr)){ + Preconditions.checkState(StringUtils.isNumeric(clientPullBatchSizeStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_PULL_BATCHSIZE)); + pullBatchSize = Integer.valueOf(clientPullBatchSizeStr); + } + + String clientPollNamesrvIntervalStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_POLL_NAMESRV_INTERVAL); + if(StringUtils.isNotEmpty(clientPollNamesrvIntervalStr)){ + Preconditions.checkState(StringUtils.isNumeric(clientPollNamesrvIntervalStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_POLL_NAMESRV_INTERVAL)); + pollNameServerInteval = Integer.valueOf(clientPollNamesrvIntervalStr); + } + + String clientHeartbeatBrokerIntervalStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_HEARTBEAT_BROKER_INTERVEL); + if(StringUtils.isNotEmpty(clientHeartbeatBrokerIntervalStr)){ + Preconditions.checkState(StringUtils.isNumeric(clientHeartbeatBrokerIntervalStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_HEARTBEAT_BROKER_INTERVEL)); + heartbeatBrokerInterval = Integer.valueOf(clientHeartbeatBrokerIntervalStr); + } + + String clientRebalanceIntervalIntervalStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_REBALANCE_INTERVEL); + if(StringUtils.isNotEmpty(clientRebalanceIntervalIntervalStr)){ + Preconditions.checkState(StringUtils.isNumeric(clientRebalanceIntervalIntervalStr), String.format("%s error", ConfKeys.KEYS_PROXY_DEFIBUS_CLIENT_REBALANCE_INTERVEL)); + rebalanceInterval = Integer.valueOf(clientRebalanceIntervalIntervalStr); + } + + +// String proxyRegisterIntervalStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_REGISTER_INTERVAL); +// if(StringUtils.isNotEmpty(proxyRegisterIntervalStr)){ +// Preconditions.checkState(StringUtils.isNumeric(proxyRegisterIntervalStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_REGISTER_INTERVAL)); +// proxyRegisterIntervalInMills = Integer.valueOf(StringUtils.deleteWhitespace(proxyRegisterIntervalStr)); +// } +// +// String proxyFetchRegistryAddrIntervalStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_FETCH_REGISTRY_ADDR_INTERVAL); +// if(StringUtils.isNotEmpty(proxyFetchRegistryAddrIntervalStr)) { +// Preconditions.checkState(StringUtils.isNumeric(proxyFetchRegistryAddrIntervalStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_FETCH_REGISTRY_ADDR_INTERVAL)); +// proxyFetchRegistryAddrInterval = Integer.valueOf(StringUtils.deleteWhitespace(proxyFetchRegistryAddrIntervalStr)); +// } + } + + static class ConfKeys { + public static String KEYS_PROXY_ENV = "proxy.server.env"; + + public static String KEYS_PROXY_REGION = "proxy.server.region"; + + public static String KEYS_PROXY_IDC = "proxy.server.idc"; + + public static String KEYS_PROXY_DCN = "proxy.server.dcn"; + + public static String KEYS_PROXY_SYSID = "proxy.sysid"; + + public static String KEYS_PROXY_SERVER_CLUSTER = "proxy.server.cluster"; + + public static String KEYS_PROXY_SERVER_NAME = "proxy.server.name"; + + public static String KEYS_PROXY_DEFIBUS_SERVICECENTER = "proxy.server.defibus.serviceCenter"; + + public static String KEYS_PROXY_DEFIBUS_CONFIGCENTER = "proxy.server.defibus.configCenter"; + + public static String KEYS_PROXY_DEFIBUS_NAMESRV_ADDR = "proxy.server.defibus.namesrvAddr"; + + public static String KEYS_PROXY_DEFIBUS_USERNAME = "proxy.server.defibus.username"; + + public static String KEYS_PROXY_DEFIBUS_PASSWORD = "proxy.server.defibus.password"; + + public static String KEYS_PROXY_DEFIBUS_CONSUME_THREADPOOL_MIN = "proxy.server.defibus.client.consumeThreadMin"; + + public static String KEYS_PROXY_DEFIBUS_CONSUME_THREADPOOL_MAX = "proxy.server.defibus.client.consumeThreadMax"; + + public static String KEYS_PROXY_DEFIBUS_CONSUME_THREADPOOL_QUEUESIZE = "proxy.server.defibus.client.consumeThreadPoolQueueSize"; + + public static String KEYS_PROXY_DEFIBUS_CLIENT_ACK_WINDOW = "proxy.server.defibus.client.ackwindow"; + + public static String KEYS_PROXY_DEFIBUS_CLIENT_PUB_WINDOW = "proxy.server.defibus.client.pubwindow"; + + public static String KEYS_PROXY_DEFIBUS_CLIENT_CONSUME_TIMEOUT = "proxy.server.defibus.client.comsumeTimeoutInMin"; + + public static String KEYS_PROXY_DEFIBUS_CLIENT_PULL_BATCHSIZE = "proxy.server.defibus.client.pullBatchSize"; + + public static String KEYS_PROXY_DEFIBUS_CLIENT_POLL_NAMESRV_INTERVAL = "proxy.server.defibus.client.pollNameServerInterval"; + + public static String KEYS_PROXY_DEFIBUS_CLIENT_HEARTBEAT_BROKER_INTERVEL = "proxy.server.defibus.client.heartbeatBrokerInterval"; + + public static String KEYS_PROXY_DEFIBUS_CLIENT_REBALANCE_INTERVEL = "proxy.server.defibus.client.rebalanceInterval"; + + public static String KEYS_PROXY_SERVER_REGISTER_INTERVAL = "proxy.server.registry.registerIntervalInMills"; + + public static String KEYS_PROXY_SERVER_FETCH_REGISTRY_ADDR_INTERVAL = "proxy.server.registry.fetchRegistryAddrIntervalInMills"; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/ConfigurationWraper.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/ConfigurationWraper.java new file mode 100644 index 0000000000..dff1e06dec --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/ConfigurationWraper.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/ConfigurationWraper.java +package cn.webank.emesher.configuration; +======== +package com.webank.runtime.configuration; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/configuration/ConfigurationWraper.java + +import cn.webank.eventmesh.common.ThreadPoolFactory; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class ConfigurationWraper { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + private String file; + + private Properties properties = new Properties(); + + private boolean reload = true; + + private ScheduledExecutorService configLoader = ThreadPoolFactory.createSingleScheduledExecutor("proxy-configloader-"); + + public ConfigurationWraper(String file, boolean reload) { + this.file = file; + this.reload = reload; + init(); + } + + private void init() { +// load(); + if (this.reload) { + configLoader.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + load(); + } + }, 30 * 1000, 30 * 1000, TimeUnit.MILLISECONDS); + } + } + + private void load() { + try { + properties.load(new BufferedReader(new FileReader( + new File(file)))); + } catch (IOException e) { + logger.error("loading properties [{}] error", file, e); + } + } + + public String getProp(String key) { + return StringUtils.isEmpty(key) ? null : properties.getProperty(key, null); + } + + +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/ProxyConfiguration.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/ProxyConfiguration.java new file mode 100644 index 0000000000..cfb8d135ed --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/ProxyConfiguration.java @@ -0,0 +1,220 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/configuration/ProxyConfiguration.java +package cn.webank.emesher.configuration; +======== +package com.webank.runtime.configuration; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/configuration/ProxyConfiguration.java + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.RateLimiter; +import org.apache.commons.lang3.StringUtils; + +public class ProxyConfiguration extends CommonConfiguration { + + public int httpServerPort = 10105; + + public RateLimiter proxyServerBatchMsgNumLimiter = RateLimiter.create(20000); + + public boolean proxyServerBatchMsgBatchEnabled = Boolean.TRUE; + + public int proxyServerBatchMsgThreadNum = 10; + + public int proxyServerSendMsgThreadNum = 8; + + public int proxyServerPushMsgThreadNum = 8; + + public int proxyServerReplyMsgThreadNum = 8; + + public int proxyServerClientManageThreadNum = 4; + + public int proxyServerRegistryThreadNum = 10; + + public int proxyServerAdminThreadNum = 2; + + public int proxyServerRetryThreadNum = 2; + + public int proxyServerPullRegistryIntervel = 30000; + + public int proxyServerAsyncAccumulationThreshold = 1000; + + public int proxyServerRetryBlockQSize = 10000; + + public int proxyServerBatchBlockQSize = 1000; + + public int proxyServerSendMsgBlockQSize = 1000; + + public int proxyServerPushMsgBlockQSize = 1000; + + public int proxyServerClientManageBlockQSize = 1000; + + public int proxyServerBusyCheckIntervel = 1000; + + public boolean proxyServerConsumerEnabled = false; + + public ProxyConfiguration(ConfigurationWraper configurationWraper){ + super(configurationWraper); + } + + public void init(){ + super.init(); + + String httpServerPortStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SERVER_HTTP_PORT); + Preconditions.checkState(StringUtils.isNotEmpty(httpServerPortStr) && StringUtils.isNumeric(httpServerPortStr), String.format("%s error", ConfKeys.KEYS_PROXY_SERVER_HTTP_PORT)); + httpServerPort = Integer.valueOf(StringUtils.deleteWhitespace(httpServerPortStr)); + + String proxyServerBatchMsgThreadNumStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_BATCHMSG_THREAD_NUM); + if (StringUtils.isNotEmpty(proxyServerBatchMsgThreadNumStr) && StringUtils.isNumeric(proxyServerBatchMsgThreadNumStr)) { + proxyServerBatchMsgThreadNum = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerBatchMsgThreadNumStr)); + } + + String proxyServerBatchMsgNumLimiterStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_BATCHMSG_RATELIMITER); + if (StringUtils.isNotEmpty(proxyServerBatchMsgNumLimiterStr) && StringUtils.isNumeric(proxyServerBatchMsgNumLimiterStr)) { + proxyServerBatchMsgNumLimiter = RateLimiter.create(Double.valueOf(StringUtils.deleteWhitespace(proxyServerBatchMsgNumLimiterStr))); + } + + String proxyServerBatchMsgBatchEnableStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_BATCHMSG_BATCH_ENABLED); + if (StringUtils.isNotBlank(proxyServerBatchMsgBatchEnableStr)) { + proxyServerBatchMsgBatchEnabled = Boolean.valueOf(proxyServerBatchMsgBatchEnableStr); + } + + String proxyServerAsyncAccumulationThresholdStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_ASYNC_ACCUMULATION_THRESHOLD); + if (StringUtils.isNotEmpty(proxyServerAsyncAccumulationThresholdStr) && StringUtils.isNumeric(proxyServerAsyncAccumulationThresholdStr)) { + proxyServerAsyncAccumulationThreshold = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerAsyncAccumulationThresholdStr)); + } + + String proxyServerSendMsgThreadNumStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_SENDMSG_THREAD_NUM); + if (StringUtils.isNotEmpty(proxyServerSendMsgThreadNumStr) && StringUtils.isNumeric(proxyServerSendMsgThreadNumStr)) { + proxyServerSendMsgThreadNum = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerSendMsgThreadNumStr)); + } + + String proxyServerReplyMsgThreadNumStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_REPLYMSG_THREAD_NUM); + if (StringUtils.isNotEmpty(proxyServerReplyMsgThreadNumStr) && StringUtils.isNumeric(proxyServerReplyMsgThreadNumStr)) { + proxyServerReplyMsgThreadNum = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerReplyMsgThreadNumStr)); + } + + String proxyServerPushMsgThreadNumStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_PUSHMSG_THREAD_NUM); + if (StringUtils.isNotEmpty(proxyServerPushMsgThreadNumStr) && StringUtils.isNumeric(proxyServerPushMsgThreadNumStr)) { + proxyServerPushMsgThreadNum = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerPushMsgThreadNumStr)); + } + + String proxyServerRegistryThreadNumStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_REGISTRY_THREAD_NUM); + if (StringUtils.isNotEmpty(proxyServerRegistryThreadNumStr) && StringUtils.isNumeric(proxyServerRegistryThreadNumStr)) { + proxyServerRegistryThreadNum = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerRegistryThreadNumStr)); + } + + String proxyServerClientManageThreadNumStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_CLIENTMANAGE_THREAD_NUM); + if (StringUtils.isNotEmpty(proxyServerClientManageThreadNumStr) && StringUtils.isNumeric(proxyServerClientManageThreadNumStr)) { + proxyServerClientManageThreadNum = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerClientManageThreadNumStr)); + } + + String proxyServerPullRegistryIntervelStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_PULL_REGISTRY_INTERVEL); + if (StringUtils.isNotEmpty(proxyServerPullRegistryIntervelStr) && StringUtils.isNumeric(proxyServerPullRegistryIntervelStr)) { + proxyServerPullRegistryIntervel = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerPullRegistryIntervelStr)); + } + + String proxyServerAdminThreadNumStr = configurationWraper.getProp(ConfKeys.KEYS_PROXY_ADMIN_THREAD_NUM); + if (StringUtils.isNotEmpty(proxyServerAdminThreadNumStr) && StringUtils.isNumeric(proxyServerAdminThreadNumStr)) { + proxyServerAdminThreadNum = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerAdminThreadNumStr)); + } + + String proxyServerRetryBlockQSizeStr = configurationWraper.getProp(ConfKeys.KEY_PROXY_RETRY_BLOCKQ_SIZE); + if (StringUtils.isNotEmpty(proxyServerRetryBlockQSizeStr) && StringUtils.isNumeric(proxyServerRetryBlockQSizeStr)) { + proxyServerRetryBlockQSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerRetryBlockQSizeStr)); + } + + String proxyServerBatchBlockQSizeStr = configurationWraper.getProp(ConfKeys.KEY_PROXY_BATCHMSG_BLOCKQ_SIZE); + if (StringUtils.isNotEmpty(proxyServerBatchBlockQSizeStr) && StringUtils.isNumeric(proxyServerBatchBlockQSizeStr)) { + proxyServerBatchBlockQSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerBatchBlockQSizeStr)); + } + + String proxyServerSendMsgBlockQSizeStr = configurationWraper.getProp(ConfKeys.KEY_PROXY_SENDMSG_BLOCKQ_SIZE); + if (StringUtils.isNotEmpty(proxyServerSendMsgBlockQSizeStr) && StringUtils.isNumeric(proxyServerSendMsgBlockQSizeStr)) { + proxyServerSendMsgBlockQSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerSendMsgBlockQSizeStr)); + } + + String proxyServerPushMsgBlockQSizeStr = configurationWraper.getProp(ConfKeys.KEY_PROXY_PUSHMSG_BLOCKQ_SIZE); + if (StringUtils.isNotEmpty(proxyServerPushMsgBlockQSizeStr) && StringUtils.isNumeric(proxyServerPushMsgBlockQSizeStr)) { + proxyServerPushMsgBlockQSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerPushMsgBlockQSizeStr)); + } + + String proxyServerClientManageBlockQSizeStr = configurationWraper.getProp(ConfKeys.KEY_PROXY_CLIENTM_BLOCKQ_SIZE); + if (StringUtils.isNotEmpty(proxyServerClientManageBlockQSizeStr) && StringUtils.isNumeric(proxyServerClientManageBlockQSizeStr)) { + proxyServerClientManageBlockQSize = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerClientManageBlockQSizeStr)); + } + + String proxyServerBusyCheckIntervelStr = configurationWraper.getProp(ConfKeys.KEY_PROXY_BUSY_CHECK_INTERVEL); + if (StringUtils.isNotEmpty(proxyServerBusyCheckIntervelStr) && StringUtils.isNumeric(proxyServerBusyCheckIntervelStr)) { + proxyServerBusyCheckIntervel = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerBusyCheckIntervelStr)); + } + + String proxyServerConsumerEnabledStr = configurationWraper.getProp(ConfKeys.KEY_PROXY_CONSUMER_ENABLED); + if (StringUtils.isNotEmpty(proxyServerConsumerEnabledStr)) { + proxyServerConsumerEnabled = Boolean.valueOf(StringUtils.deleteWhitespace(proxyServerConsumerEnabledStr)); + } + + String proxyServerRetryThreadNumStr = configurationWraper.getProp(ConfKeys.KEY_PROXY_RETRY_THREAD_NUM); + if (StringUtils.isNotEmpty(proxyServerRetryThreadNumStr) && StringUtils.isNumeric(proxyServerRetryThreadNumStr)) { + proxyServerRetryThreadNum = Integer.valueOf(StringUtils.deleteWhitespace(proxyServerRetryThreadNumStr)); + } + } + + static class ConfKeys{ + + public static String KEYS_PROXY_SERVER_HTTP_PORT = "proxy.server.http.port"; + + public static String KEYS_PROXY_BATCHMSG_THREAD_NUM = "proxy.server.batchmsg.threads.num"; + + public static String KEYS_PROXY_BATCHMSG_RATELIMITER = "proxy.server.batchmsg.speed.ratelimiter"; + + public static String KEYS_PROXY_BATCHMSG_BATCH_ENABLED = "proxy.server.batchmsg.batch.enabled"; + + public static String KEYS_PROXY_ASYNC_ACCUMULATION_THRESHOLD = "proxy.server.async.accumulation.threshold"; + + public static String KEY_PROXY_BUSY_CHECK_INTERVEL = "proxy.server.busy.check.intervel"; + + public static String KEYS_PROXY_SENDMSG_THREAD_NUM = "proxy.server.sendmsg.threads.num"; + + public static String KEYS_PROXY_REPLYMSG_THREAD_NUM = "proxy.server.replymsg.threads.num"; + + public static String KEYS_PROXY_PUSHMSG_THREAD_NUM = "proxy.server.pushmsg.threads.num"; + + public static String KEYS_PROXY_REGISTRY_THREAD_NUM = "proxy.server.registry.threads.num"; + + public static String KEYS_PROXY_CLIENTMANAGE_THREAD_NUM = "proxy.server.clientmanage.threads.num"; + + public static String KEYS_PROXY_ADMIN_THREAD_NUM = "proxy.server.admin.threads.num"; + + public static String KEY_PROXY_RETRY_THREAD_NUM = "proxy.server.retry.threads.num"; + + public static String KEYS_PROXY_PULL_REGISTRY_INTERVEL = "proxy.server.pull.registry.intervel"; + + public static String KEY_PROXY_RETRY_BLOCKQ_SIZE = "proxy.server.retry.blockQ.size"; + + public static String KEY_PROXY_BATCHMSG_BLOCKQ_SIZE = "proxy.server.batchmsg.blockQ.size"; + + public static String KEY_PROXY_SENDMSG_BLOCKQ_SIZE = "proxy.server.sendmsg.blockQ.size"; + + public static String KEY_PROXY_PUSHMSG_BLOCKQ_SIZE = "proxy.server.pushmsg.blockQ.size"; + + public static String KEY_PROXY_CLIENTM_BLOCKQ_SIZE = "proxy.server.clientM.blockQ.size"; + + public static String KEY_PROXY_CONSUMER_ENABLED = "proxy.server.consumer.enabled"; + + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/constants/ProxyConstants.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/constants/ProxyConstants.java new file mode 100644 index 0000000000..efcd8e00ad --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/constants/ProxyConstants.java @@ -0,0 +1,120 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/constants/ProxyConstants.java +package cn.webank.emesher.constants; +======== +package com.webank.runtime.constants; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/constants/ProxyConstants.java + +public class ProxyConstants { + + public static final String PROTOCOL_HTTP = "http"; + + public static final String PROTOCOL_TCP = "tcp"; + + public static final String HTTP_DOMAIN_NAME = "proxy-" + PROTOCOL_HTTP; + + public static final String TCP_DOMAIN_NAME = "proxy-" + PROTOCOL_TCP; + + public static final String BROADCAST_PREFIX = "broadcast-"; + + public static final String DEFAULT_CHARSET = "UTF-8"; + + public static final String IP_PORT_SEPARATOR = ":"; + + public static final String HTTP_PROTOCOL_PREFIX = "http://"; + + public static final String PROXY_SERVICE_PREFIX = "proxy-server-"; + + public static final String REGEX_VALIDATE_FOR_ENDPOINTS = "^(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:\\d{4,6};)*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:\\d{4,6})$"; + + public static final String PROXY_CONF_HOME = System.getProperty("confPath", System.getenv("confPath")); + + public static final String PROXY_CONF_FILE = "proxy.properties"; + + public static final String REQ_C2PROXY_TIMESTAMP = "req_c2access_timestamp"; + public static final String REQ_PROXY2MQ_TIMESTAMP = "req_access2mq_timestamp"; + public static final String REQ_MQ2PROXY_TIMESTAMP = "req_mq2access_timestamp"; + public static final String REQ_PROXY2C_TIMESTAMP = "req_access2c_timestamp"; + public static final String RSP_C2PROXY_TIMESTAMP = "rsp_c2access_timestamp"; + public static final String RSP_PROXY2MQ_TIMESTAMP = "rsp_access2mq_timestamp"; + public static final String RSP_MQ2PROXY_TIMESTAMP = "rsp_mq2access_timestamp"; + public static final String RSP_PROXY2C_TIMESTAMP = "rsp_access2c_timestamp"; + + public static final String REQ_SEND_PROXY_IP = "req_send_proxy_ip"; + public static final String REQ_RECEIVE_PROXY_IP = "req_receive_proxy_ip"; + public static final String RSP_SEND_PROXY_IP = "rsp_send_proxy_ip"; + public static final String RSP_RECEIVE_PROXY_IP = "rsp_receive_proxy_ip"; + + //add for mss-trace + public static final String REQ_BORN_TIMESTAMP = "req_born_timestamp"; + public static final String REQ_STORE_TIMESTAMP = "req_store_timestamp"; + public static final String REQ_LEAVE_TIMESTAMP = "req_leave_timestamp"; + public static final String REQ_ARRIVE_TIMESTAMP = "req_arrive_timestamp"; + + //默认TTL 4 小时 + public static final Integer DEFAULT_MSG_TTL_MILLS = 14400000; + + public static final int DEFAULT_TIMEOUT_IN_MILLISECONDS = 3000; + + public static final int DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS = 100; + + public static final int DEFAULT_PUSH_RETRY_TIMES = 3; + + public static final int DEFAULT_PUSH_RETRY_TIME_DISTANCE_IN_MILLSECONDS = 3000; + + public static final String PURPOSE_PUB = "pub"; + + public static final String PURPOSE_SUB = "sub"; + + public static final String PURPOSE_ALL = "all"; + + public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; + + + public static final String BORN_TIMESTAMP = "BORN_TIME"; + public static final String STORE_TIMESTAMP = "STORE_TIME"; + public static final String LEAVE_TIMESTAMP = "LEAVE_TIME"; + public static final String ARRIVE_TIMESTAMP = "ARRIVE_TIME"; + + public static final String KEYS_UPPERCASE = "KEYS"; + public static final String KEYS_LOWERCASE = "keys"; + public static final String RR_REQUEST_UNIQ_ID = "RR_REQUEST_UNIQ_ID"; + public static final String TTL = "TTL"; + + public static final String TAG = "TAG"; + + public static final String MANAGE_SUBSYSTEM = "subSystem"; + public static final String MANAGE_IP = "ip"; + public static final String MANAGE_PORT = "port"; + public static final String MANAGE_DEST_IP = "destProxyIp"; + public static final String MANAGE_DEST_PORT = "destProxyPort"; + public static final String MANAGE_PATH = "path"; + public static final String MANAGE_GROUP = "group"; + public static final String MANAGE_PURPOSE = "purpose"; + public static final String MANAGE_TOPIC = "topic"; + + public static final String PROXY_SEND_BACK_TIMES= "proxySendBackTimes"; + + public static final String PROXY_SEND_BACK_IP= "proxySendBackIp"; + + public static final String PROXY_REGISTRY_ADDR_KEY= "proxyRegistryAddr"; + + public static int DEFAULT_TIME_OUT_MILLS = 5 * 1000; + +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/constants/ProxyVersion.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/constants/ProxyVersion.java new file mode 100644 index 0000000000..b708c1ee7c --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/constants/ProxyVersion.java @@ -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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/constants/ProxyVersion.java +package cn.webank.emesher.constants; +======== +package com.webank.runtime.constants; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/constants/ProxyVersion.java + +public class ProxyVersion { + + public static final String CURRENT_VERSION = Version.V3_0_0.name(); + + public static String getCurrentVersionDesc() { + return CURRENT_VERSION.replaceAll("V", "") + .replaceAll("_", ".") + .replaceAll("_SNAPSHOT", "-SNAPSHOT"); + } + + public enum Version { + V3_0_0, + V3_0_1, + V3_1_0, + V3_2_0, + V3_3_0 + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ConsumerGroupConf.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ConsumerGroupConf.java new file mode 100644 index 0000000000..ce51791eb0 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ConsumerGroupConf.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ConsumerGroupConf.java +package cn.webank.emesher.core.consumergroup; +======== +package com.webank.runtime.core.consumergroup; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/consumergroup/ConsumerGroupConf.java + +import com.google.common.collect.Maps; + +import java.util.Map; +import java.util.Objects; + +public class ConsumerGroupConf { + //eg . 5013-1A0 + private String consumerGroup; + + private Map consumerGroupTopicConf = Maps.newConcurrentMap(); + + public ConsumerGroupConf(String consumerGroup) { + this.consumerGroup = consumerGroup; + } + + public String getConsumerGroup() { + return consumerGroup; + } + + public void setConsumerGroup(String consumerGroup) { + this.consumerGroup = consumerGroup; + } + + public Map getConsumerGroupTopicConf() { + return consumerGroupTopicConf; + } + + public void setConsumerGroupTopicConf(Map consumerGroupTopicConf) { + this.consumerGroupTopicConf = consumerGroupTopicConf; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConsumerGroupConf that = (ConsumerGroupConf) o; + return consumerGroup.equals(that.consumerGroup) && + Objects.equals(consumerGroupTopicConf, that.consumerGroupTopicConf); + } + + @Override + public int hashCode() { + return Objects.hash(consumerGroup, consumerGroupTopicConf); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("consumerGroupConfig={") + .append("groupName=").append(consumerGroup).append(",") + .append(",consumerGroupTopicConf=").append(consumerGroupTopicConf).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ConsumerGroupTopicConf.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ConsumerGroupTopicConf.java new file mode 100644 index 0000000000..1b6bf715be --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ConsumerGroupTopicConf.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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ConsumerGroupTopicConf.java +package cn.webank.emesher.core.consumergroup; +======== +package com.webank.runtime.core.consumergroup; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/consumergroup/ConsumerGroupTopicConf.java + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +public class ConsumerGroupTopicConf { + + public static Logger logger = LoggerFactory.getLogger(ConsumerGroupTopicConf.class); + + private String consumerGroup; + + private String topic; + + /** + * PUSH的URL + */ + private Map /** IDC内URL列表*/> idcUrls = Maps.newConcurrentMap(); + + /** + * IDC 无关的全量URL + */ + private Set urls = Sets.newConcurrentHashSet(); + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConsumerGroupTopicConf that = (ConsumerGroupTopicConf) o; + return consumerGroup.equals(that.consumerGroup) && + Objects.equals(topic, that.topic) && + Objects.equals(idcUrls, that.idcUrls); + } + + @Override + public int hashCode() { + return Objects.hash(consumerGroup, topic, idcUrls); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("consumeTopicConfig={consumerGroup=").append(consumerGroup) + .append(",topic=").append(topic) + .append(",idcUrls=").append(idcUrls).append("}"); + return sb.toString(); + } + + public String getConsumerGroup() { + return consumerGroup; + } + + public void setConsumerGroup(String consumerGroup) { + this.consumerGroup = consumerGroup; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public Map> getIdcUrls() { + return idcUrls; + } + + public void setIdcUrls(Map> idcUrls) { + this.idcUrls = idcUrls; + } + + public Set getUrls() { + return urls; + } + + public void setUrls(Set urls) { + this.urls = urls; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ProducerGroupConf.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ProducerGroupConf.java new file mode 100644 index 0000000000..81a877dfbd --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ProducerGroupConf.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/ProducerGroupConf.java +package cn.webank.emesher.core.consumergroup; +======== +package com.webank.runtime.core.consumergroup; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/consumergroup/ProducerGroupConf.java + +import java.util.Objects; + +public class ProducerGroupConf { + private String groupName; + + public ProducerGroupConf(String groupName) { + this.groupName = groupName; + } + + public String getGroupName() { + return groupName; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("producerGroupConfig={") + .append("groupName=").append(groupName).append("}"); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ProducerGroupConf that = (ProducerGroupConf) o; + return groupName == that.groupName; + } + + @Override + public int hashCode() { + return Objects.hash(groupName); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupInstanceChangeEvent.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupInstanceChangeEvent.java new file mode 100644 index 0000000000..170c642c26 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupInstanceChangeEvent.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupInstanceChangeEvent.java +package cn.webank.emesher.core.consumergroup.event; +======== +package com.webank.runtime.core.consumergroup.event; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/consumergroup/event/ConsumerGroupInstanceChangeEvent.java + +public class ConsumerGroupInstanceChangeEvent { +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupStateEvent.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupStateEvent.java new file mode 100644 index 0000000000..a5c84082e7 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupStateEvent.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupStateEvent.java +package cn.webank.emesher.core.consumergroup.event; + +import cn.webank.emesher.core.consumergroup.ConsumerGroupConf; +======== +package com.webank.runtime.core.consumergroup.event; + +import com.webank.runtime.core.consumergroup.ConsumerGroupConf; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/consumergroup/event/ConsumerGroupStateEvent.java + +public class ConsumerGroupStateEvent { + + public String consumerGroup; + public ConsumerGroupStateAction action; + public ConsumerGroupConf consumerGroupConfig; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("consumerGroupStateEvent={") + .append("consumerGroup=").append(consumerGroup) + .append(",action=").append(action).append("}"); + return sb.toString(); + } + + + public enum ConsumerGroupStateAction { + NEW, + CHANGE, + DELETE + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupTopicConfChangeEvent.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupTopicConfChangeEvent.java new file mode 100644 index 0000000000..d6abf025f7 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupTopicConfChangeEvent.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/consumergroup/event/ConsumerGroupTopicConfChangeEvent.java +package cn.webank.emesher.core.consumergroup.event; + +import cn.webank.emesher.core.consumergroup.ConsumerGroupTopicConf; +======== +package com.webank.runtime.core.consumergroup.event; + +import com.webank.runtime.core.consumergroup.ConsumerGroupTopicConf; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/consumergroup/event/ConsumerGroupTopicConfChangeEvent.java + +public class ConsumerGroupTopicConfChangeEvent { + + public ConsumerGroupTopicConfChangeAction action; + + public String topic; + + public String consumerGroup; + + public ConsumerGroupTopicConf newTopicConf; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("consumerGroupTopicConfChangeEvent={") + .append("consumerGroup=").append(consumerGroup).append(",") + .append("topic=").append(topic).append(",") + .append("action=").append(action).append("}"); + return sb.toString(); + } + + public enum ConsumerGroupTopicConfChangeAction { + NEW, + CHANGE, + DELETE + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/async/AsyncContext.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/async/AsyncContext.java new file mode 100644 index 0000000000..4b58b41bb2 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/async/AsyncContext.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/async/AsyncContext.java +package cn.webank.emesher.core.protocol.http.async; +======== +package com.webank.runtime.core.protocol.http.async; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/async/AsyncContext.java + +import com.google.common.base.Preconditions; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicBoolean; + +public class AsyncContext { + + private T request; + + private T response; + + private AtomicBoolean complete = new AtomicBoolean(Boolean.FALSE); + + private ThreadPoolExecutor asyncContextExecutor; + + public AsyncContext(T request, T response, ThreadPoolExecutor asyncContextExecutor) { + Preconditions.checkState(request != null, "create async context err because of request is null"); + this.request = request; + this.response = response; + this.asyncContextExecutor = asyncContextExecutor; + } + + public void onComplete(final T response) { + Preconditions.checkState(Objects.nonNull(response), "response cant be null"); + this.response = response; + this.complete.compareAndSet(Boolean.FALSE, Boolean.TRUE); + } + + public void onComplete(final T response, CompleteHandler handler) { + Preconditions.checkState(Objects.nonNull(response), "response cant be null"); + Preconditions.checkState(Objects.nonNull(handler), "handler cant be null"); + this.response = response; + CompletableFuture.runAsync(() -> { + handler.onResponse(response); + }, asyncContextExecutor); + this.complete.compareAndSet(Boolean.FALSE, Boolean.TRUE); + } + + public boolean isComplete() { + return complete.get(); + } + + public T getRequest() { + return request; + } + + public void setRequest(T request) { + this.request = request; + } + + public T getResponse() { + return response; + } + + public void setResponse(T response) { + this.response = response; + } + + public ThreadPoolExecutor getAsyncContextExecutor() { + return asyncContextExecutor; + } + + public void setAsyncContextExecutor(ThreadPoolExecutor asyncContextExecutor) { + this.asyncContextExecutor = asyncContextExecutor; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/async/CompleteHandler.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/async/CompleteHandler.java new file mode 100644 index 0000000000..83853608fd --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/async/CompleteHandler.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/async/CompleteHandler.java +package cn.webank.emesher.core.protocol.http.async; +======== +package com.webank.runtime.core.protocol.http.async; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/async/CompleteHandler.java + +public interface CompleteHandler { + void onResponse(T t); +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ConsumerGroupManager.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ConsumerGroupManager.java new file mode 100644 index 0000000000..46e8bcf9bb --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ConsumerGroupManager.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ConsumerGroupManager.java +package cn.webank.emesher.core.protocol.http.consumer; + +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.core.consumergroup.ConsumerGroupConf; +======== +package com.webank.runtime.core.protocol.http.consumer; + +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.core.consumergroup.ConsumerGroupConf; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/consumer/ConsumerGroupManager.java + +import java.util.concurrent.atomic.AtomicBoolean; + +public class ConsumerGroupManager { + + protected AtomicBoolean started = new AtomicBoolean(Boolean.FALSE); + + protected AtomicBoolean inited = new AtomicBoolean(Boolean.FALSE); + + private ProxyHTTPServer proxyHTTPServer; + + private ProxyConsumer proxyConsumer; + + private ConsumerGroupConf consumerGroupConfig; + + public ConsumerGroupManager(ProxyHTTPServer proxyHTTPServer, ConsumerGroupConf consumerGroupConfig) { + this.proxyHTTPServer = proxyHTTPServer; + this.consumerGroupConfig = consumerGroupConfig; + proxyConsumer = new ProxyConsumer(this.proxyHTTPServer, this.consumerGroupConfig); + } + + public synchronized void init() throws Exception { + proxyConsumer.init(); + inited.compareAndSet(false, true); + } + + public synchronized void start() throws Exception { + steupProxyConsumer(consumerGroupConfig); + proxyConsumer.start(); + started.compareAndSet(false, true); + } + + private synchronized void steupProxyConsumer(ConsumerGroupConf consumerGroupConfig) throws Exception { + for(String topic:consumerGroupConfig.getConsumerGroupTopicConf().keySet()) { + proxyConsumer.subscribe(topic); + } + } + + public synchronized void shutdown() throws Exception { + proxyConsumer.shutdown(); + started.compareAndSet(true, false); + } + + public synchronized void refresh(ConsumerGroupConf consumerGroupConfig) throws Exception { + + if(consumerGroupConfig == null || this.consumerGroupConfig.equals(consumerGroupConfig)) { + return; + } + + if(started.get()) { + shutdown(); + } + + this.consumerGroupConfig = consumerGroupConfig; + init(); + start(); + } + + public ConsumerGroupConf getConsumerGroupConfig() { + return consumerGroupConfig; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ConsumerManager.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ConsumerManager.java new file mode 100644 index 0000000000..16a36923aa --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ConsumerManager.java @@ -0,0 +1,174 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ConsumerManager.java +package cn.webank.emesher.core.protocol.http.consumer; + +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.core.consumergroup.ConsumerGroupConf; +import cn.webank.emesher.core.consumergroup.event.ConsumerGroupStateEvent; +import cn.webank.emesher.core.consumergroup.event.ConsumerGroupTopicConfChangeEvent; +======== +package com.webank.runtime.core.protocol.http.consumer; + +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.core.consumergroup.ConsumerGroupConf; +import com.webank.runtime.core.consumergroup.event.ConsumerGroupStateEvent; +import com.webank.runtime.core.consumergroup.event.ConsumerGroupTopicConfChangeEvent; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/consumer/ConsumerManager.java +import com.google.common.eventbus.Subscribe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +public class ConsumerManager { + + private ProxyHTTPServer proxyHTTPServer; + + private ConcurrentHashMap consumerTable = new ConcurrentHashMap(); + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public ConsumerManager(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + public void init() throws Exception { + proxyHTTPServer.getEventBus().register(this); + logger.info("consumerManager inited......"); + } + + public void start() throws Exception { + logger.info("consumerManager started......"); + } + + public void shutdown() { + proxyHTTPServer.getEventBus().unregister(this); + for (ConsumerGroupManager consumerGroupManager : consumerTable.values()) { + try { + consumerGroupManager.shutdown(); + } catch (Exception ex) { + logger.error("shutdown consumerGroupManager[{}] err", consumerGroupManager, ex); + } + } + logger.info("consumerManager shutdown......"); + } + + public boolean contains(String consumerGroup) { + return consumerTable.containsKey(consumerGroup); + } + + /** + * 新增消费者 + * + * @param consumerGroup + * @param consumerGroupConfig + * @throws Exception + */ + public synchronized void addConsumer(String consumerGroup, ConsumerGroupConf consumerGroupConfig) throws Exception { + ConsumerGroupManager cgm = new ConsumerGroupManager(proxyHTTPServer, consumerGroupConfig); + cgm.init(); + cgm.start(); + consumerTable.put(consumerGroup, cgm); + } + + /** + * 重启消费者DeleteOnExitHook + */ + public synchronized void restartConsumer(String consumerGroup, ConsumerGroupConf consumerGroupConfig) throws Exception { + ConsumerGroupManager cgm = consumerTable.get(consumerGroup); + cgm.refresh(consumerGroupConfig); + } + + /** + * 重启消费者 + */ + public ConsumerGroupManager getConsumer(String consumerGroup) throws Exception { + ConsumerGroupManager cgm = consumerTable.get(consumerGroup); + return cgm; + } + + /** + * 删除消费者 + * + * @param consumerGroup + */ + public synchronized void delConsumer(String consumerGroup) throws Exception { + ConsumerGroupManager cgm = consumerTable.remove(consumerGroup); + cgm.shutdown(); + } + + @Subscribe + public void onChange(ConsumerGroupTopicConfChangeEvent event) { + try { + logger.info("onChange event:{}", event); + if (event.action == ConsumerGroupTopicConfChangeEvent.ConsumerGroupTopicConfChangeAction.NEW) { + ConsumerGroupManager manager = getConsumer(event.consumerGroup); + if (Objects.isNull(manager)) { + return; + } + manager.getConsumerGroupConfig().getConsumerGroupTopicConf().put(event.topic, event.newTopicConf); + return; + } + + if (event.action == ConsumerGroupTopicConfChangeEvent.ConsumerGroupTopicConfChangeAction.CHANGE) { + ConsumerGroupManager manager = getConsumer(event.consumerGroup); + if (Objects.isNull(manager)) { + return; + } + manager.getConsumerGroupConfig().getConsumerGroupTopicConf().replace(event.topic, event.newTopicConf); + return; + } + + if (event.action == ConsumerGroupTopicConfChangeEvent.ConsumerGroupTopicConfChangeAction.DELETE) { + ConsumerGroupManager manager = getConsumer(event.consumerGroup); + if (Objects.isNull(manager)) { + return; + } + manager.getConsumerGroupConfig().getConsumerGroupTopicConf().remove(event.topic); + return; + } + } catch (Exception ex) { + logger.error("onChange event:{} err", event, ex); + } + } + + @Subscribe + public void onChange(ConsumerGroupStateEvent event) { + try { + logger.info("onChange event:{}", event); + if (event.action == ConsumerGroupStateEvent.ConsumerGroupStateAction.NEW) { + addConsumer(event.consumerGroup, event.consumerGroupConfig); + return; + } + + if (event.action == ConsumerGroupStateEvent.ConsumerGroupStateAction.CHANGE) { + restartConsumer(event.consumerGroup, event.consumerGroupConfig); + return; + } + + if (event.action == ConsumerGroupStateEvent.ConsumerGroupStateAction.DELETE) { + delConsumer(event.consumerGroup); + return; + } + } catch (Exception ex) { + logger.error("onChange event:{} err", event, ex); + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/HandleMsgContext.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/HandleMsgContext.java new file mode 100644 index 0000000000..be968808cb --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/HandleMsgContext.java @@ -0,0 +1,240 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/HandleMsgContext.java +package cn.webank.emesher.core.protocol.http.consumer; + +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.consumergroup.ConsumerGroupConf; +import cn.webank.emesher.core.consumergroup.ConsumerGroupTopicConf; +import cn.webank.eventmesh.common.Constants; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyContext; +======== +package com.webank.runtime.core.protocol.http.consumer; + +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.consumergroup.ConsumerGroupConf; +import com.webank.runtime.core.consumergroup.ConsumerGroupTopicConf; +import com.webank.eventmesh.common.Constants; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import com.webank.runtime.patch.ProxyConsumeConcurrentlyContext; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/consumer/HandleMsgContext.java +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +public class HandleMsgContext { + + public Logger messageLogger = LoggerFactory.getLogger("message"); + + private String msgRandomNo; + + private String consumerGroup; + + private ProxyConsumer proxyConsumer; + + private String bizSeqNo; + + private String uniqueId; + + private String topic; + + private MessageExt msg; + + private int ttl; + + private long createTime = System.currentTimeMillis(); + + private ConsumeMessageConcurrentlyContext context; + + private ConsumerGroupConf consumerGroupConfig; + + private ProxyHTTPServer proxyHTTPServer; + + private ConsumerGroupTopicConf consumeTopicConfig; + + private Map props; + + public HandleMsgContext(String msgRandomNo, String consumerGroup, ProxyConsumer proxyConsumer, + String topic, MessageExt msg, + ConsumeConcurrentlyContext context, ConsumerGroupConf consumerGroupConfig, + ProxyHTTPServer proxyHTTPServer, String bizSeqNo, String uniqueId, ConsumerGroupTopicConf consumeTopicConfig) { + this.msgRandomNo = msgRandomNo; + this.consumerGroup = consumerGroup; + this.proxyConsumer = proxyConsumer; + this.topic = topic; + this.msg = msg; + this.context = (ConsumeMessageConcurrentlyContext)context; + this.consumerGroupConfig = consumerGroupConfig; + this.proxyHTTPServer = proxyHTTPServer; + this.bizSeqNo = bizSeqNo; + this.uniqueId = uniqueId; + this.consumeTopicConfig = consumeTopicConfig; + this.ttl = MapUtils.getIntValue(msg.getProperties(), DeFiBusConstant.PROPERTY_MESSAGE_TTL, ProxyConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); + } + + public void addProp(String key, String val) { + if (props == null) { + props = new HashMap<>(); + } + props.put(key, val); + } + + public String getProp(String key) { + return props.get(key); + } + + public String getMsgRandomNo() { + return msgRandomNo; + } + + public void setMsgRandomNo(String msgRandomNo) { + this.msgRandomNo = msgRandomNo; + } + + public ConsumerGroupTopicConf getConsumeTopicConfig() { + return consumeTopicConfig; + } + + public void setConsumeTopicConfig(ConsumerGroupTopicConf consumeTopicConfig) { + this.consumeTopicConfig = consumeTopicConfig; + } + + public String getBizSeqNo() { + return bizSeqNo; + } + + public void setBizSeqNo(String bizSeqNo) { + this.bizSeqNo = bizSeqNo; + } + + public String getConsumerGroup() { + return consumerGroup; + } + + public void setConsumerGroup(String consumerGroup) { + this.consumerGroup = consumerGroup; + } + + public ProxyConsumer getProxyConsumer() { + return proxyConsumer; + } + + public void setProxyConsumer(ProxyConsumer proxyConsumer) { + this.proxyConsumer = proxyConsumer; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public MessageExt getMsg() { + return msg; + } + + public void setMsg(MessageExt msg) { + this.msg = msg; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public ConsumeConcurrentlyContext getContext() { + return context; + } + + public void setContext(ConsumeMessageConcurrentlyContext context) { + this.context = context; + } + + public ConsumerGroupConf getConsumerGroupConfig() { + return consumerGroupConfig; + } + + public void setConsumerGroupConfig(ConsumerGroupConf consumerGroupConfig) { + this.consumerGroupConfig = consumerGroupConfig; + } + + public ProxyHTTPServer getProxyHTTPServer() { + return proxyHTTPServer; + } + + public void finish() { + if (proxyConsumer != null && context != null && msg != null) { + if (messageLogger.isDebugEnabled()) { + messageLogger.debug("messageAcked|topic={}|msgId={}|cluster={}|broker={}|queueId={}|queueOffset={}", topic, + msg.getMsgId(), msg.getProperty(DeFiBusConstant.PROPERTY_MESSAGE_CLUSTER), + msg.getProperty(DeFiBusConstant.PROPERTY_MESSAGE_BROKER), + msg.getQueueId(), msg.getQueueOffset()); + } + proxyConsumer.updateOffset(topic, Arrays.asList(msg), context); + } + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public int getTtl() { + return ttl; + } + + public void setTtl(int ttl) { + this.ttl = ttl; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("handleMsgContext={") + .append("consumerGroup=").append(consumerGroup) + .append(",topic=").append(topic) + .append(",consumeTopicConfig=").append(consumeTopicConfig) + .append(",bizSeqNo=").append(bizSeqNo) + .append(",uniqueId=").append(uniqueId) + .append(",ttl=").append(ttl) + .append(",createTime=").append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ProxyConsumer.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ProxyConsumer.java new file mode 100644 index 0000000000..f632fdfdcd --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/consumer/ProxyConsumer.java @@ -0,0 +1,290 @@ +/* + * 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 cn.webank.emesher.core.protocol.http.consumer; + +import cn.webank.defibus.client.common.DeFiBusClientConfig; +import cn.webank.defibus.consumer.DeFiBusMessageListenerConcurrently; +import cn.webank.defibus.consumer.DeFiBusPushConsumer; +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.consumergroup.ConsumerGroupConf; +import cn.webank.emesher.core.consumergroup.ConsumerGroupTopicConf; +import cn.webank.emesher.core.protocol.http.producer.ProxyProducer; +import cn.webank.emesher.core.protocol.http.producer.SendMessageContext; +import cn.webank.emesher.core.protocol.http.push.HTTPMessageHandler; +import cn.webank.emesher.core.protocol.http.push.MessageHandler; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.ThreadUtil; +import cn.webank.emesher.util.ProxyUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyContext; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageService; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +public class ProxyConsumer extends DeFiBusMessageListenerConcurrently { + + private ProxyHTTPServer proxyHTTPServer; + + private AtomicBoolean started4Persistent = new AtomicBoolean(Boolean.FALSE); + + private AtomicBoolean started4Broadcast = new AtomicBoolean(Boolean.FALSE); + + private AtomicBoolean inited4Persistent = new AtomicBoolean(Boolean.FALSE); + + private AtomicBoolean inited4Broadcast = new AtomicBoolean(Boolean.FALSE); + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public Logger messageLogger = LoggerFactory.getLogger("message"); + + private ConsumerGroupConf consumerGroupConf; + + private DeFiBusPushConsumer persistentMsgConsumer; + + private DeFiBusClientConfig clientConfig4Clustering; + + private DeFiBusClientConfig clientConfig4Broadcasting; + + private DeFiBusPushConsumer broadCastMsgConsumer; + + public ProxyConsumer(ProxyHTTPServer proxyHTTPServer, ConsumerGroupConf consumerGroupConf) { + this.proxyHTTPServer = proxyHTTPServer; + this.consumerGroupConf = consumerGroupConf; + } + + private MessageHandler httpMessageHandler = new HTTPMessageHandler(this); + + private DeFiBusClientConfig initDeFiBusClientConfig(boolean broadcast) { + DeFiBusClientConfig wcc = new DeFiBusClientConfig(); + wcc.setPollNameServerInterval(proxyHTTPServer.getProxyConfiguration().pollNameServerInteval); + wcc.setHeartbeatBrokerInterval(proxyHTTPServer.getProxyConfiguration().heartbeatBrokerInterval); + wcc.setAckWindowSize(proxyHTTPServer.getProxyConfiguration().ackWindow); + wcc.setThreadPoolCoreSize(proxyHTTPServer.getProxyConfiguration().consumeThreadMin); + wcc.setThreadPoolMaxSize(proxyHTTPServer.getProxyConfiguration().consumeThreadMax); + wcc.setPubWindowSize(proxyHTTPServer.getProxyConfiguration().pubWindow); + wcc.setPullBatchSize(proxyHTTPServer.getProxyConfiguration().pullBatchSize); + wcc.setClusterPrefix(proxyHTTPServer.getProxyConfiguration().proxyIDC); + + if (broadcast) { + wcc.setConsumerGroup(ProxyConstants.CONSUMER_GROUP_NAME_PREFIX + ProxyConstants.BROADCAST_PREFIX + consumerGroupConf.getConsumerGroup()); + } else { + wcc.setConsumerGroup(ProxyConstants.CONSUMER_GROUP_NAME_PREFIX + consumerGroupConf.getConsumerGroup()); + } + + if (StringUtils.isEmpty(proxyHTTPServer.getProxyConfiguration().namesrvAddr)) { + wcc.setWsAddr(ProxyUtil.buildCCAddr(proxyHTTPServer.getProxyConfiguration().configCenterAddr, + proxyHTTPServer.getProxyConfiguration().proxyIDC)); + } else { + wcc.setNamesrvAddr(proxyHTTPServer.getProxyConfiguration().namesrvAddr); + } + return wcc; + } + + public synchronized void init() throws Exception { + clientConfig4Broadcasting = initDeFiBusClientConfig(true); + clientConfig4Clustering = initDeFiBusClientConfig(false); + persistentMsgConsumer = new DeFiBusPushConsumer(clientConfig4Clustering); + broadCastMsgConsumer = new DeFiBusPushConsumer(clientConfig4Broadcasting); + inited4Broadcast.compareAndSet(false, true); + inited4Persistent.compareAndSet(false, true); + logger.info("ProxyConsumer [{}] inited.............", consumerGroupConf.getConsumerGroup()); + } + + public synchronized void start() throws Exception { + ThreadUtil.randomSleep(50); + logger.info("persistentMsgConsumerClientConfig : " + clientConfig4Clustering); + logger.info("directMsgConsumerClientConfig : " + clientConfig4Broadcasting); + if (!started4Persistent.get()) { + persistentMsgConsumer.getDefaultMQPushConsumer().setInstanceName(ProxyUtil.buildProxyClientID(consumerGroupConf.getConsumerGroup(), + proxyHTTPServer.getProxyConfiguration().proxyRegion, + proxyHTTPServer.getProxyConfiguration().proxyCluster)); + persistentMsgConsumer.getDefaultMQPushConsumer().setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); + persistentMsgConsumer.getDefaultMQPushConsumer().setMessageModel(MessageModel.CLUSTERING); + persistentMsgConsumer.registerMessageListener(this); + persistentMsgConsumer.start(); + persistentMsgConsumer.getDefaultMQPushConsumer().unsubscribe(MixAll.getRetryTopic(clientConfig4Clustering.getConsumerGroup())); + logger.info("ProxyConsumer cluster consumer [{}] started.............", consumerGroupConf.getConsumerGroup()); + } + + if (!started4Broadcast.get()) { + broadCastMsgConsumer.getDefaultMQPushConsumer().setInstanceName(ProxyUtil.buildProxyClientID(consumerGroupConf.getConsumerGroup(), + proxyHTTPServer.getProxyConfiguration().proxyRegion, + proxyHTTPServer.getProxyConfiguration().proxyCluster)); + broadCastMsgConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); + broadCastMsgConsumer.getDefaultMQPushConsumer().setMessageModel(MessageModel.BROADCASTING); + broadCastMsgConsumer.registerMessageListener(this); + broadCastMsgConsumer.start(); + broadCastMsgConsumer.getDefaultMQPushConsumer().unsubscribe(MixAll.getRetryTopic(clientConfig4Broadcasting.getConsumerGroup())); + + logger.info("ProxyConsumer broadcast consumer [{}] started.............", consumerGroupConf.getConsumerGroup()); + } + + started4Persistent.compareAndSet(false, true); + started4Broadcast.compareAndSet(false, true); + + } + + public void subscribe(String topic) throws Exception { + if (ProxyUtil.isBroadcast(topic)) { + broadCastMsgConsumer.subscribe(topic); + } else { + persistentMsgConsumer.subscribe(topic); + } + } + + public void unsubscribe(String topic) throws Exception { + if (ProxyUtil.isBroadcast(topic)) { + broadCastMsgConsumer.unsubscribe(topic); + } else { + persistentMsgConsumer.unsubscribe(topic); + } + } + + public boolean isPause() { + return persistentMsgConsumer.getDefaultMQPushConsumer().getDefaultMQPushConsumerImpl().isPause() + && broadCastMsgConsumer.getDefaultMQPushConsumer().getDefaultMQPushConsumerImpl().isPause(); + } + + public void pause() { + broadCastMsgConsumer.getDefaultMQPushConsumer().getDefaultMQPushConsumerImpl().setPause(true); + persistentMsgConsumer.getDefaultMQPushConsumer().getDefaultMQPushConsumerImpl().setPause(true); + } + + public synchronized void shutdown() throws Exception { + if (started4Broadcast.get()) { + broadCastMsgConsumer.shutdown(); + logger.info("ProxyConsumer broadcast consumer [{}] shutdown.............", consumerGroupConf.getConsumerGroup()); + } + + if (started4Persistent.get()) { + persistentMsgConsumer.shutdown(); + logger.info("ProxyConsumer cluster consumer [{}] shutdown.............", consumerGroupConf.getConsumerGroup()); + } + + started4Broadcast.compareAndSet(true, false); + started4Persistent.compareAndSet(true, false); + } + + public void updateOffset(String topic, List msgs, ConsumeMessageConcurrentlyContext context) { + if (ProxyUtil.isBroadcast(topic)) { + ConsumeMessageService consumeMessageService = broadCastMsgConsumer.getDefaultMQPushConsumer().getDefaultMQPushConsumerImpl().getConsumeMessageService(); + ((ConsumeMessageConcurrentlyService)consumeMessageService).updateOffset(msgs, context); + } else { + ConsumeMessageService consumeMessageService = persistentMsgConsumer.getDefaultMQPushConsumer().getDefaultMQPushConsumerImpl().getConsumeMessageService(); + ((ConsumeMessageConcurrentlyService)consumeMessageService).updateOffset(msgs, context); + } + } + + public ConsumerGroupConf getConsumerGroupConf() { + return consumerGroupConf; + } + + public ProxyHTTPServer getProxyHTTPServer() { + return proxyHTTPServer; + } + + public void sendMessageBack(final MessageExt msgBack, final String uniqueId, String bizSeqNo) throws Exception { + + ProxyProducer sendMessageBack + = proxyHTTPServer.getProducerManager().getProxyProducer(ProxyConstants.PRODUCER_GROUP_NAME_PREFIX + + consumerGroupConf.getConsumerGroup()); + + if (sendMessageBack == null) { + logger.warn("consumer:{} consume fail, sendMessageBack, bizSeqNo:{}, uniqueId:{}", consumerGroupConf.getConsumerGroup(), bizSeqNo, uniqueId); + return; + } + + final SendMessageContext sendMessageBackContext = new SendMessageContext(bizSeqNo, msgBack, sendMessageBack, proxyHTTPServer); + + sendMessageBack.send(sendMessageBackContext, new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + } + + @Override + public void onException(Throwable e) { + logger.warn("consumer:{} consume fail, sendMessageBack, bizSeqno:{}, uniqueId:{}", consumerGroupConf.getConsumerGroup(), bizSeqNo, uniqueId); + } + }); + } + + @Override + public ConsumeConcurrentlyStatus handleMessage(List msgs, ConsumeConcurrentlyContext context) { + if (CollectionUtils.isEmpty(msgs)) + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + + MessageExt msg = msgs.get(0); + String topic = msg.getTopic(); + + if (!ProxyUtil.isValidRMBTopic(topic)) { + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + + String bizSeqNo = msg.getKeys(); + String uniqueId = MapUtils.getString(msg.getProperties(), Constants.RMB_UNIQ_ID, ""); + + msg.putUserProperty(ProxyConstants.REQ_MQ2PROXY_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + + if (messageLogger.isDebugEnabled()) { + messageLogger.debug("message|mq2proxy|topic={}|msg={}", topic, msg); + } else { + messageLogger.info("message|mq2proxy|topic={}|bizSeqNo={}|uniqueId={}", topic, bizSeqNo, uniqueId); + } + + ConsumerGroupTopicConf currentTopicConfig = MapUtils.getObject(consumerGroupConf.getConsumerGroupTopicConf(), topic, null); + + if (currentTopicConfig == null) { + logger.error("no topicConfig found, consumerGroup:{} topic:{}", consumerGroupConf.getConsumerGroup(), topic); + try { + sendMessageBack(msg, uniqueId, bizSeqNo); + } catch (Exception ex) { + } + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + + HandleMsgContext handleMsgContext = new HandleMsgContext(ProxyUtil.buildPushMsgSeqNo(), consumerGroupConf.getConsumerGroup(), this, + msg.getTopic(), msg, context, consumerGroupConf, proxyHTTPServer, bizSeqNo, uniqueId, currentTopicConfig); + + if (httpMessageHandler.handle(handleMsgContext)) { + ((ConsumeMessageConcurrentlyContext)context).setManualAck(true); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + + try { + sendMessageBack(msg, uniqueId, bizSeqNo); + } catch (Exception ex) { + } + + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/AdminMetricsProcessor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/AdminMetricsProcessor.java new file mode 100644 index 0000000000..176d93a5a7 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/AdminMetricsProcessor.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/AdminMetricsProcessor.java +package cn.webank.emesher.core.protocol.http.processor; + +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.emesher.core.protocol.http.processor.inf.HttpRequestProcessor; +import cn.webank.eventmesh.common.command.HttpCommand; +======== +package com.webank.runtime.core.protocol.http.processor; + +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import com.webank.eventmesh.common.command.HttpCommand; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/processor/AdminMetricsProcessor.java +import io.netty.channel.ChannelHandlerContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AdminMetricsProcessor implements HttpRequestProcessor { + + public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + + private ProxyHTTPServer proxyHTTPServer; + + public AdminMetricsProcessor(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { + } + + @Override + public boolean rejectRequest() { + return false; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/AdminShutdownProcessor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/AdminShutdownProcessor.java new file mode 100644 index 0000000000..c2565ef2a9 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/AdminShutdownProcessor.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/AdminShutdownProcessor.java +package cn.webank.emesher.core.protocol.http.processor; + +import cn.webank.emesher.boot.ProxyServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.emesher.core.protocol.http.processor.inf.HttpRequestProcessor; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.command.HttpCommand; +import cn.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +======== +package com.webank.runtime.core.protocol.http.processor; + +import com.webank.runtime.boot.ProxyServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import com.webank.eventmesh.common.IPUtil; +import com.webank.eventmesh.common.command.HttpCommand; +import com.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/processor/AdminShutdownProcessor.java +import io.netty.channel.ChannelHandlerContext; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AdminShutdownProcessor implements HttpRequestProcessor { + + public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + + private ProxyServer proxyServer; + + public AdminShutdownProcessor(ProxyServer proxyServer) { + this.proxyServer = proxyServer; + } + + @Override + public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { + + HttpCommand responseProxyCommand; + cmdLogger.info("cmd={}|{}|client2proxy|from={}|to={}", RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), + ProxyConstants.PROTOCOL_HTTP, + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtil.getLocalAddress()); + + proxyServer.shutdown(); + + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + ProxyRetCode.SUCCESS.getRetCode(), ProxyRetCode.SUCCESS.getErrMsg()); + asyncContext.onComplete(responseProxyCommand); + } + + @Override + public boolean rejectRequest() { + return false; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/BatchSendMessageProcessor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/BatchSendMessageProcessor.java new file mode 100644 index 0000000000..35f2796d4c --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/BatchSendMessageProcessor.java @@ -0,0 +1,276 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/BatchSendMessageProcessor.java +package cn.webank.emesher.core.protocol.http.processor; + +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.emesher.core.protocol.http.processor.inf.HttpRequestProcessor; +import cn.webank.emesher.core.protocol.http.producer.ProxyProducer; +import cn.webank.emesher.core.protocol.http.producer.SendMessageContext; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.command.HttpCommand; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageBatchRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageBatchResponseBody; +import cn.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageBatchRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageBatchResponseHeader; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.core.protocol.http.processor; + +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import com.webank.runtime.core.protocol.http.producer.ProxyProducer; +import com.webank.runtime.core.protocol.http.producer.SendMessageContext; +import com.webank.eventmesh.common.IPUtil; +import com.webank.eventmesh.common.command.HttpCommand; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageBatchRequestBody; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageBatchResponseBody; +import com.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +import com.webank.eventmesh.common.protocol.http.header.message.SendMessageBatchRequestHeader; +import com.webank.eventmesh.common.protocol.http.header.message.SendMessageBatchResponseHeader; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/processor/BatchSendMessageProcessor.java +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.Validators; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageBatch; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +public class BatchSendMessageProcessor implements HttpRequestProcessor { + + public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + + private ProxyHTTPServer proxyHTTPServer; + + public BatchSendMessageProcessor(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + public Logger batchMessageLogger = LoggerFactory.getLogger("batchMessage"); + + public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { + + HttpCommand responseProxyCommand; + + cmdLogger.info("cmd={}|{}|client2proxy|from={}|to={}", RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), + ProxyConstants.PROTOCOL_HTTP, + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtil.getLocalAddress()); + + SendMessageBatchRequestHeader sendMessageBatchRequestHeader = (SendMessageBatchRequestHeader) asyncContext.getRequest().getHeader(); + SendMessageBatchRequestBody sendMessageBatchRequestBody = (SendMessageBatchRequestBody) asyncContext.getRequest().getBody(); + + SendMessageBatchResponseHeader sendMessageBatchResponseHeader = + SendMessageBatchResponseHeader.buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), proxyHTTPServer.getProxyConfiguration().proxyCluster, + IPUtil.getLocalAddress(), proxyHTTPServer.getProxyConfiguration().proxyEnv, + proxyHTTPServer.getProxyConfiguration().proxyRegion, + proxyHTTPServer.getProxyConfiguration().proxyDCN, proxyHTTPServer.getProxyConfiguration().proxyIDC); + + if (StringUtils.isBlank(sendMessageBatchRequestHeader.getPid()) + || !StringUtils.isNumeric(sendMessageBatchRequestHeader.getPid()) + || StringUtils.isBlank(sendMessageBatchRequestHeader.getSys())) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchResponseHeader, + SendMessageBatchResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + if (CollectionUtils.isEmpty(sendMessageBatchRequestBody.getContents()) + || StringUtils.isBlank(sendMessageBatchRequestBody.getBatchId()) + || (Integer.valueOf(sendMessageBatchRequestBody.getSize()) != CollectionUtils.size(sendMessageBatchRequestBody.getContents()))) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchResponseHeader, + SendMessageBatchResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + if (!proxyHTTPServer.getProxyConfiguration().proxyServerBatchMsgNumLimiter + .tryAcquire(Integer.valueOf(sendMessageBatchRequestBody.getSize()), ProxyConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchResponseHeader, + SendMessageBatchResponseBody.buildBody(ProxyRetCode.PROXY_BATCH_SPEED_OVER_LIMIT_ERR.getRetCode(), ProxyRetCode.PROXY_BATCH_SPEED_OVER_LIMIT_ERR.getErrMsg())); + proxyHTTPServer.metrics.summaryMetrics + .recordSendBatchMsgDiscard(Integer.valueOf(sendMessageBatchRequestBody.getSize())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + if (StringUtils.isBlank(sendMessageBatchRequestHeader.getDcn())) { + sendMessageBatchRequestHeader.setDcn("BATCH"); + } + String producerGroup = ProxyUtil.buildClientGroup(sendMessageBatchRequestHeader.getSys(), + sendMessageBatchRequestHeader.getDcn()); + ProxyProducer batchProxyProducer = proxyHTTPServer.getProducerManager().getProxyProducer(producerGroup); + + batchProxyProducer.getDefibusProducer().getDeFiBusClientConfig().setRetryTimesWhenSendFailed(0); + batchProxyProducer.getDefibusProducer().getDeFiBusClientConfig().setRetryTimesWhenSendAsyncFailed(0); + batchProxyProducer.getDefibusProducer().getDeFiBusClientConfig().setPollNameServerInterval(60000); + + batchProxyProducer.getDefibusProducer().getDefaultMQProducer().setCompressMsgBodyOverHowmuch(10); + batchProxyProducer.getDefibusProducer().getDefaultMQProducer().getDefaultMQProducerImpl().getmQClientFactory() + .getNettyClientConfig() + .setClientAsyncSemaphoreValue(proxyHTTPServer.getProxyConfiguration().proxyServerAsyncAccumulationThreshold); + + if (!batchProxyProducer.getStarted().get()) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchResponseHeader, + SendMessageBatchResponseBody.buildBody(ProxyRetCode.PROXY_BATCH_PRODUCER_STOPED_ERR.getRetCode(), ProxyRetCode.PROXY_BATCH_PRODUCER_STOPED_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + long batchStartTime = System.currentTimeMillis(); + + List msgList = new ArrayList<>(); + Map> topicBatchMessageMappings = new ConcurrentHashMap>(); + for (SendMessageBatchRequestBody.BatchMessageEntity msg : sendMessageBatchRequestBody.getContents()) { + if (StringUtils.isBlank(msg.topic) + || StringUtils.isBlank(msg.msg)) { + continue; + } + + if (StringUtils.isBlank(msg.ttl) || !StringUtils.isNumeric(msg.ttl)) { + msg.ttl = String.valueOf(ProxyConstants.DEFAULT_MSG_TTL_MILLS); + } + + try { + Message rocketMQMsg; + if (StringUtils.isBlank(msg.tag)) { + rocketMQMsg = new Message(msg.topic, msg.msg.getBytes(ProxyConstants.DEFAULT_CHARSET)); + } else { + rocketMQMsg = new Message(msg.topic, msg.tag, msg.msg.getBytes(ProxyConstants.DEFAULT_CHARSET)); + } + rocketMQMsg.putUserProperty(DeFiBusConstant.KEY, DeFiBusConstant.PERSISTENT); + rocketMQMsg.putUserProperty(DeFiBusConstant.PROPERTY_MESSAGE_TTL, msg.ttl); + msgList.add(rocketMQMsg); + if (topicBatchMessageMappings.containsKey(msg.topic)) { + topicBatchMessageMappings.get(msg.topic).add(rocketMQMsg); + } else { + List tmp = new ArrayList<>(); + tmp.add(rocketMQMsg); + topicBatchMessageMappings.put(msg.topic, tmp); + } + + if (batchMessageLogger.isDebugEnabled()) { + batchMessageLogger.debug("msg2MQMsg suc, msg:{}", msg.msg); + } + + } catch (Exception e) { + batchMessageLogger.error("msg2MQMsg err, msg:{}", msg, e); + } + } + + if (CollectionUtils.isEmpty(msgList)) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchResponseHeader, + SendMessageBatchResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + proxyHTTPServer.metrics.summaryMetrics.recordSendBatchMsg(Integer.valueOf(sendMessageBatchRequestBody.getSize())); + + if (proxyHTTPServer.getProxyConfiguration().proxyServerBatchMsgBatchEnabled) { + for (List batchMsgs : topicBatchMessageMappings.values()) { + MessageBatch msgBatch; + try { + msgBatch = MessageBatch.generateFromList(batchMsgs); + for (Message message : msgBatch) { + Validators.checkMessage(message, batchProxyProducer.getDefibusProducer().getDefaultMQProducer()); + MessageClientIDSetter.setUniqID(message); + } + msgBatch.setBody(msgBatch.encode()); + } catch (Exception e) { + continue; + } + + final SendMessageContext sendMessageContext = new SendMessageContext(sendMessageBatchRequestBody.getBatchId(), msgBatch, batchProxyProducer, proxyHTTPServer); + batchProxyProducer.send(sendMessageContext, new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + } + + @Override + public void onException(Throwable e) { + batchMessageLogger.warn("", e); + proxyHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); + } + }); + } + } else { + for (Message msg : msgList) { + final SendMessageContext sendMessageContext = new SendMessageContext(sendMessageBatchRequestBody.getBatchId(), msg, batchProxyProducer, proxyHTTPServer); + batchProxyProducer.send(sendMessageContext, new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + + } + + @Override + public void onException(Throwable e) { + batchMessageLogger.warn("", e); + proxyHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); + } + }); + } + } + + long batchEndTime = System.currentTimeMillis(); + proxyHTTPServer.metrics.summaryMetrics.recordBatchSendMsgCost(batchEndTime - batchStartTime); + batchMessageLogger.debug("batchMessage|proxy2mq|REQ|ASYNC|batchId={}|send2MQCost={}ms|msgNum={}|topics={}", + sendMessageBatchRequestBody.getBatchId(), + batchEndTime - batchStartTime, + sendMessageBatchRequestBody.getSize(), + topicBatchMessageMappings.keySet()); + + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchResponseHeader, + SendMessageBatchResponseBody.buildBody(ProxyRetCode.SUCCESS.getRetCode(), ProxyRetCode.SUCCESS.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + + return; + } + + @Override + public boolean rejectRequest() { + return false; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/BatchSendMessageV2Processor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/BatchSendMessageV2Processor.java new file mode 100644 index 0000000000..f1f90a6da4 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/BatchSendMessageV2Processor.java @@ -0,0 +1,234 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/BatchSendMessageV2Processor.java +package cn.webank.emesher.core.protocol.http.processor; + +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.emesher.core.protocol.http.processor.inf.HttpRequestProcessor; +import cn.webank.emesher.core.protocol.http.producer.ProxyProducer; +import cn.webank.emesher.core.protocol.http.producer.SendMessageContext; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.command.HttpCommand; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageBatchV2RequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageBatchV2ResponseBody; +import cn.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageBatchV2RequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageBatchV2ResponseHeader; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.core.protocol.http.processor; + +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import com.webank.runtime.core.protocol.http.producer.ProxyProducer; +import com.webank.runtime.core.protocol.http.producer.SendMessageContext; +import com.webank.eventmesh.common.IPUtil; +import com.webank.eventmesh.common.command.HttpCommand; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageBatchV2RequestBody; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageBatchV2ResponseBody; +import com.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +import com.webank.eventmesh.common.protocol.http.header.message.SendMessageBatchV2RequestHeader; +import com.webank.eventmesh.common.protocol.http.header.message.SendMessageBatchV2ResponseHeader; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/processor/BatchSendMessageV2Processor.java +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.TimeUnit; + +public class BatchSendMessageV2Processor implements HttpRequestProcessor { + + public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + + private ProxyHTTPServer proxyHTTPServer; + + public BatchSendMessageV2Processor(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + public Logger batchMessageLogger = LoggerFactory.getLogger("batchMessage"); + + public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { + + HttpCommand responseProxyCommand; + + cmdLogger.info("cmd={}|{}|client2proxy|from={}|to={}", RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), + ProxyConstants.PROTOCOL_HTTP, + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtil.getLocalAddress()); + + SendMessageBatchV2RequestHeader sendMessageBatchV2RequestHeader = (SendMessageBatchV2RequestHeader) asyncContext.getRequest().getHeader(); + SendMessageBatchV2RequestBody sendMessageBatchV2RequestBody = (SendMessageBatchV2RequestBody) asyncContext.getRequest().getBody(); + + SendMessageBatchV2ResponseHeader sendMessageBatchV2ResponseHeader = + SendMessageBatchV2ResponseHeader.buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), proxyHTTPServer.getProxyConfiguration().proxyCluster, + IPUtil.getLocalAddress(), proxyHTTPServer.getProxyConfiguration().proxyEnv, + proxyHTTPServer.getProxyConfiguration().proxyRegion, + proxyHTTPServer.getProxyConfiguration().proxyDCN, proxyHTTPServer.getProxyConfiguration().proxyIDC); + + if (StringUtils.isBlank(sendMessageBatchV2RequestHeader.getPid()) + || !StringUtils.isNumeric(sendMessageBatchV2RequestHeader.getPid()) + || StringUtils.isBlank(sendMessageBatchV2RequestHeader.getSys())) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchV2ResponseHeader, + SendMessageBatchV2ResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + if (StringUtils.isBlank(sendMessageBatchV2RequestBody.getBizSeqNo()) + || StringUtils.isBlank(sendMessageBatchV2RequestBody.getTopic()) + || StringUtils.isBlank(sendMessageBatchV2RequestBody.getMsg())) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchV2ResponseHeader, + SendMessageBatchV2ResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + if (!proxyHTTPServer.getProxyConfiguration().proxyServerBatchMsgNumLimiter + .tryAcquire(ProxyConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchV2ResponseHeader, + SendMessageBatchV2ResponseBody.buildBody(ProxyRetCode.PROXY_BATCH_SPEED_OVER_LIMIT_ERR.getRetCode(), ProxyRetCode.PROXY_BATCH_SPEED_OVER_LIMIT_ERR.getErrMsg())); + proxyHTTPServer.metrics.summaryMetrics + .recordSendBatchMsgDiscard(1); + asyncContext.onComplete(responseProxyCommand); + return; + } + + if (StringUtils.isBlank(sendMessageBatchV2RequestHeader.getDcn())) { + sendMessageBatchV2RequestHeader.setDcn("BATCH"); + } + String producerGroup = ProxyUtil.buildClientGroup(sendMessageBatchV2RequestHeader.getSys(), + sendMessageBatchV2RequestHeader.getDcn()); + ProxyProducer batchProxyProducer = proxyHTTPServer.getProducerManager().getProxyProducer(producerGroup); + batchProxyProducer.getDefibusProducer().getDeFiBusClientConfig().setRetryTimesWhenSendFailed(0); + batchProxyProducer.getDefibusProducer().getDeFiBusClientConfig().setRetryTimesWhenSendAsyncFailed(0); + batchProxyProducer.getDefibusProducer().getDeFiBusClientConfig().setPollNameServerInterval(60000); + + batchProxyProducer.getDefibusProducer().getDefaultMQProducer().getDefaultMQProducerImpl().getmQClientFactory() + .getNettyClientConfig().setClientAsyncSemaphoreValue(proxyHTTPServer.getProxyConfiguration().proxyServerAsyncAccumulationThreshold); + batchProxyProducer.getDefibusProducer().getDefaultMQProducer().setCompressMsgBodyOverHowmuch(10); + if (!batchProxyProducer.getStarted().get()) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchV2ResponseHeader, + SendMessageBatchV2ResponseBody.buildBody(ProxyRetCode.PROXY_BATCH_PRODUCER_STOPED_ERR.getRetCode(), ProxyRetCode.PROXY_BATCH_PRODUCER_STOPED_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + long batchStartTime = System.currentTimeMillis(); + + if (StringUtils.isBlank(sendMessageBatchV2RequestBody.getTtl()) || !StringUtils.isNumeric(sendMessageBatchV2RequestBody.getTtl())) { + sendMessageBatchV2RequestBody.setTtl(String.valueOf(ProxyConstants.DEFAULT_MSG_TTL_MILLS)); + } + + Message rocketMQMsg = null; + + try { + if (StringUtils.isBlank(sendMessageBatchV2RequestBody.getTag())) { + rocketMQMsg = new Message(sendMessageBatchV2RequestBody.getTopic(), sendMessageBatchV2RequestBody.getMsg().getBytes(ProxyConstants.DEFAULT_CHARSET)); + } else { + rocketMQMsg = new Message(sendMessageBatchV2RequestBody.getTopic(), sendMessageBatchV2RequestBody.getTag(), + sendMessageBatchV2RequestBody.getMsg().getBytes(ProxyConstants.DEFAULT_CHARSET)); + } + rocketMQMsg.putUserProperty(DeFiBusConstant.KEY, DeFiBusConstant.PERSISTENT); + rocketMQMsg.putUserProperty(DeFiBusConstant.PROPERTY_MESSAGE_TTL, sendMessageBatchV2RequestBody.getTtl()); + + if (batchMessageLogger.isDebugEnabled()) { + batchMessageLogger.debug("msg2MQMsg suc, topic:{}, msg:{}", sendMessageBatchV2RequestBody.getTopic(), sendMessageBatchV2RequestBody.getMsg()); + } + + } catch (Exception e) { + batchMessageLogger.error("msg2MQMsg err, topic:{}, msg:{}", sendMessageBatchV2RequestBody.getTopic(), sendMessageBatchV2RequestBody.getMsg(), e); + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchV2ResponseHeader, + SendMessageBatchV2ResponseBody.buildBody(ProxyRetCode.PROXY_PACKAGE_MSG_ERR.getRetCode(), ProxyRetCode.PROXY_PACKAGE_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(e, 2))); + asyncContext.onComplete(responseProxyCommand); + return; + } + + proxyHTTPServer.metrics.summaryMetrics.recordSendBatchMsg(1); + + final SendMessageContext sendMessageContext = new SendMessageContext(sendMessageBatchV2RequestBody.getBizSeqNo(), rocketMQMsg, batchProxyProducer, proxyHTTPServer); + + try { + batchProxyProducer.send(sendMessageContext, new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + long batchEndTime = System.currentTimeMillis(); + proxyHTTPServer.metrics.summaryMetrics.recordBatchSendMsgCost(batchEndTime - batchStartTime); + batchMessageLogger.debug("batchMessageV2|proxy2mq|REQ|ASYNC|bizSeqNo={}|send2MQCost={}ms|topic={}", + sendMessageBatchV2RequestBody.getBizSeqNo(), + batchEndTime - batchStartTime, + sendMessageBatchV2RequestBody.getTopic()); + } + + @Override + public void onException(Throwable e) { + long batchEndTime = System.currentTimeMillis(); + proxyHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); + proxyHTTPServer.metrics.summaryMetrics.recordBatchSendMsgCost(batchEndTime - batchStartTime); + batchMessageLogger.error("batchMessageV2|proxy2mq|REQ|ASYNC|bizSeqNo={}|send2MQCost={}ms|topic={}", + sendMessageBatchV2RequestBody.getBizSeqNo(), + batchEndTime - batchStartTime, + sendMessageBatchV2RequestBody.getTopic(), e); + } + }); + } catch (Exception e) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchV2ResponseHeader, + SendMessageBatchV2ResponseBody.buildBody(ProxyRetCode.PROXY_SEND_BATCHLOG_MSG_ERR.getRetCode(), ProxyRetCode.PROXY_SEND_BATCHLOG_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(e, 2))); + asyncContext.onComplete(responseProxyCommand); + long batchEndTime = System.currentTimeMillis(); + proxyHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); + proxyHTTPServer.metrics.summaryMetrics.recordBatchSendMsgCost(batchEndTime - batchStartTime); + batchMessageLogger.error("batchMessageV2|proxy2mq|REQ|ASYNC|bizSeqNo={}|send2MQCost={}ms|topic={}", + sendMessageBatchV2RequestBody.getBizSeqNo(), + batchEndTime - batchStartTime, + sendMessageBatchV2RequestBody.getTopic(), e); + } + + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageBatchV2ResponseHeader, + SendMessageBatchV2ResponseBody.buildBody(ProxyRetCode.SUCCESS.getRetCode(), ProxyRetCode.SUCCESS.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + + return; + } + + @Override + public boolean rejectRequest() { + return false; + } +} + diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/ReplyMessageProcessor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/ReplyMessageProcessor.java new file mode 100644 index 0000000000..d3441e9476 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/ReplyMessageProcessor.java @@ -0,0 +1,268 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/ReplyMessageProcessor.java +package cn.webank.emesher.core.protocol.http.processor; + +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.emesher.core.protocol.http.async.CompleteHandler; +import cn.webank.emesher.core.protocol.http.processor.inf.HttpRequestProcessor; +import cn.webank.emesher.core.protocol.http.producer.ProxyProducer; +import cn.webank.emesher.core.protocol.http.producer.SendMessageContext; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.LiteMessage; +import cn.webank.eventmesh.common.command.HttpCommand; +import cn.webank.eventmesh.common.protocol.http.body.message.ReplyMessageRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.ReplyMessageResponseBody; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import cn.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.eventmesh.common.protocol.http.header.message.ReplyMessageRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.ReplyMessageResponseHeader; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.core.protocol.http.processor; + +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.runtime.core.protocol.http.async.CompleteHandler; +import com.webank.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import com.webank.runtime.core.protocol.http.producer.ProxyProducer; +import com.webank.runtime.core.protocol.http.producer.SendMessageContext; +import com.webank.eventmesh.common.IPUtil; +import com.webank.eventmesh.common.LiteMessage; +import com.webank.eventmesh.common.command.HttpCommand; +import com.webank.eventmesh.common.protocol.http.body.message.ReplyMessageRequestBody; +import com.webank.eventmesh.common.protocol.http.body.message.ReplyMessageResponseBody; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import com.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +import com.webank.eventmesh.common.protocol.http.header.message.ReplyMessageRequestHeader; +import com.webank.eventmesh.common.protocol.http.header.message.ReplyMessageResponseHeader; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/processor/ReplyMessageProcessor.java +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class ReplyMessageProcessor implements HttpRequestProcessor { + + public Logger messageLogger = LoggerFactory.getLogger("message"); + + public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + + public Logger httpLogger = LoggerFactory.getLogger("http"); + + private ProxyHTTPServer proxyHTTPServer; + + public ReplyMessageProcessor(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + @Override + public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { + HttpCommand responseProxyCommand; + + cmdLogger.info("cmd={}|{}|client2proxy|from={}|to={}", RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), + ProxyConstants.PROTOCOL_HTTP, + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtil.getLocalAddress()); + + ReplyMessageRequestHeader replyMessageRequestHeader = (ReplyMessageRequestHeader) asyncContext.getRequest().getHeader(); + ReplyMessageRequestBody replyMessageRequestBody = (ReplyMessageRequestBody) asyncContext.getRequest().getBody(); + + ReplyMessageResponseHeader replyMessageResponseHeader = + ReplyMessageResponseHeader.buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), proxyHTTPServer.getProxyConfiguration().proxyCluster, + IPUtil.getLocalAddress(), proxyHTTPServer.getProxyConfiguration().proxyEnv, + proxyHTTPServer.getProxyConfiguration().proxyRegion, + proxyHTTPServer.getProxyConfiguration().proxyDCN, proxyHTTPServer.getProxyConfiguration().proxyIDC); + + //HEADER校验 + if (StringUtils.isBlank(replyMessageRequestHeader.getIdc()) + || StringUtils.isBlank(replyMessageRequestHeader.getDcn()) + || StringUtils.isBlank(replyMessageRequestHeader.getPid()) + || !StringUtils.isNumeric(replyMessageRequestHeader.getPid()) + || StringUtils.isBlank(replyMessageRequestHeader.getSys())) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + replyMessageResponseHeader, + ReplyMessageResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + //BODY校验 + if (StringUtils.isBlank(replyMessageRequestBody.getBizSeqNo()) + || StringUtils.isBlank(replyMessageRequestBody.getUniqueId()) + || StringUtils.isBlank(replyMessageRequestBody.getContent())) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + replyMessageResponseHeader, + ReplyMessageResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + String producerGroup = ProxyUtil.buildClientGroup(replyMessageRequestHeader.getSys(), + replyMessageRequestHeader.getDcn()); + ProxyProducer proxyProducer = proxyHTTPServer.getProducerManager().getProxyProducer(producerGroup); + + if (!proxyProducer.getStarted().get()) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + replyMessageResponseHeader, + ReplyMessageResponseBody.buildBody(ProxyRetCode.PROXY_GROUP_PRODUCER_STOPED_ERR.getRetCode(), ProxyRetCode.PROXY_GROUP_PRODUCER_STOPED_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + long startTime = System.currentTimeMillis(); + + Message rocketMQMsg; + + String replyTopic = DeFiBusConstant.RR_REPLY_TOPIC; + + Map extFields = replyMessageRequestBody.getExtFields(); + final String replyMQCluster = MapUtils.getString(extFields, DeFiBusConstant.PROPERTY_MESSAGE_CLUSTER, null); + if (!org.apache.commons.lang3.StringUtils.isEmpty(replyMQCluster)) { + replyTopic = replyMQCluster + "-" + replyTopic; + } else { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + replyMessageResponseHeader, + ReplyMessageResponseBody.buildBody(ProxyRetCode.PROXY_REPLY_MSG_ERR.getRetCode(), ProxyRetCode.PROXY_REPLY_MSG_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + try { + rocketMQMsg = new Message(replyTopic, + replyMessageRequestBody.getContent().getBytes(ProxyConstants.DEFAULT_CHARSET)); + + rocketMQMsg.putUserProperty(DeFiBusConstant.KEY, DeFiBusConstant.PERSISTENT); + for (Map.Entry entry : extFields.entrySet()) { + rocketMQMsg.putUserProperty(entry.getKey(), entry.getValue()); + } + + rocketMQMsg.putUserProperty(DeFiBusConstant.PROPERTY_MESSAGE_TTL, String.valueOf(ProxyConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS)); + rocketMQMsg.getProperties().put(ProxyConstants.REQ_C2PROXY_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + if (messageLogger.isDebugEnabled()) { + messageLogger.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", replyMessageRequestBody.getBizSeqNo(), + replyTopic); + } + + } catch (Exception e) { + messageLogger.error("msg2MQMsg err, bizSeqNo={}, topic={}", replyMessageRequestBody.getBizSeqNo(), + replyTopic, e); + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + replyMessageResponseHeader, + ReplyMessageResponseBody.buildBody(ProxyRetCode.PROXY_PACKAGE_MSG_ERR.getRetCode(), ProxyRetCode.PROXY_PACKAGE_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(e, 2))); + asyncContext.onComplete(responseProxyCommand); + return; + } + + final SendMessageContext sendMessageContext = new SendMessageContext(replyMessageRequestBody.getBizSeqNo(), rocketMQMsg, proxyProducer, proxyHTTPServer); + proxyHTTPServer.metrics.summaryMetrics.recordReplyMsg(); + + CompleteHandler handler = new CompleteHandler() { + @Override + public void onResponse(HttpCommand httpCommand) { + try { + if (httpLogger.isDebugEnabled()) { + httpLogger.debug("{}", httpCommand); + } + proxyHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); + proxyHTTPServer.metrics.summaryMetrics.recordHTTPReqResTimeCost(System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); + } catch (Exception ex) { + } + } + }; + + LiteMessage liteMessage = new LiteMessage(replyMessageRequestBody.getBizSeqNo(), + replyMessageRequestBody.getUniqueId(), replyMessageRequestBody.getOrigTopic(), + replyMessageRequestBody.getContent()); + + try { + sendMessageContext.getMsg().getProperties().put(ProxyConstants.REQ_PROXY2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + proxyProducer.reply(sendMessageContext, new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + HttpCommand succ = asyncContext.getRequest().createHttpCommandResponse( + replyMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.SUCCESS.getRetCode(), ProxyRetCode.SUCCESS.getErrMsg())); + asyncContext.onComplete(succ, handler); + long endTime = System.currentTimeMillis(); + proxyHTTPServer.metrics.summaryMetrics.recordReplyMsgCost(endTime - startTime); + messageLogger.info("message|proxy2mq|RSP|SYNC|reply2MQCost={}|topic={}|origTopic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, + replyMQCluster + "-" + DeFiBusConstant.RR_REPLY_TOPIC, + replyMessageRequestBody.getOrigTopic(), + replyMessageRequestBody.getBizSeqNo(), + replyMessageRequestBody.getUniqueId()); + } + + @Override + public void onException(Throwable e) { + HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( + replyMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_REPLY_MSG_ERR.getRetCode(), + ProxyRetCode.PROXY_REPLY_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(e, 2))); + asyncContext.onComplete(err, handler); + long endTime = System.currentTimeMillis(); + proxyHTTPServer.metrics.summaryMetrics.recordReplyMsgFailed(); + proxyHTTPServer.metrics.summaryMetrics.recordReplyMsgCost(endTime - startTime); + messageLogger.error("message|proxy2mq|RSP|SYNC|reply2MQCost={}|topic={}|origTopic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, + replyMQCluster + "-" + DeFiBusConstant.RR_REPLY_TOPIC, + replyMessageRequestBody.getOrigTopic(), + replyMessageRequestBody.getBizSeqNo(), + replyMessageRequestBody.getUniqueId(), e); + } + }); + } catch (Exception ex) { + HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( + replyMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_REPLY_MSG_ERR.getRetCode(), + ProxyRetCode.PROXY_REPLY_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(ex, 2))); + asyncContext.onComplete(err); + long endTime = System.currentTimeMillis(); + messageLogger.error("message|proxy2mq|RSP|SYNC|reply2MQCost={}|topic={}|origTopic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, + replyTopic, + replyMessageRequestBody.getOrigTopic(), + replyMessageRequestBody.getBizSeqNo(), + replyMessageRequestBody.getUniqueId(), ex); + proxyHTTPServer.metrics.summaryMetrics.recordReplyMsgFailed(); + proxyHTTPServer.metrics.summaryMetrics.recordReplyMsgCost(endTime - startTime); + } + + return; + } + + @Override + public boolean rejectRequest() { + return false; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SendAsyncMessageProcessor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SendAsyncMessageProcessor.java new file mode 100644 index 0000000000..580ac59047 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SendAsyncMessageProcessor.java @@ -0,0 +1,262 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SendAsyncMessageProcessor.java +package cn.webank.emesher.core.protocol.http.processor; + +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.emesher.core.protocol.http.async.CompleteHandler; +import cn.webank.emesher.core.protocol.http.processor.inf.HttpRequestProcessor; +import cn.webank.emesher.core.protocol.http.producer.ProxyProducer; +import cn.webank.emesher.core.protocol.http.producer.SendMessageContext; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.LiteMessage; +import cn.webank.eventmesh.common.command.HttpCommand; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import cn.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageResponseHeader; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.core.protocol.http.processor; + +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.runtime.core.protocol.http.async.CompleteHandler; +import com.webank.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import com.webank.runtime.core.protocol.http.producer.ProxyProducer; +import com.webank.runtime.core.protocol.http.producer.SendMessageContext; +import com.webank.eventmesh.common.Constants; +import com.webank.eventmesh.common.IPUtil; +import com.webank.eventmesh.common.LiteMessage; +import com.webank.eventmesh.common.command.HttpCommand; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import com.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +import com.webank.eventmesh.common.protocol.http.header.message.SendMessageRequestHeader; +import com.webank.eventmesh.common.protocol.http.header.message.SendMessageResponseHeader; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/processor/SendAsyncMessageProcessor.java +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SendAsyncMessageProcessor implements HttpRequestProcessor { + + public Logger messageLogger = LoggerFactory.getLogger("message"); + + public Logger httpLogger = LoggerFactory.getLogger("http"); + + public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + + private ProxyHTTPServer proxyHTTPServer; + + public SendAsyncMessageProcessor(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + @Override + public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { + + HttpCommand responseProxyCommand; + + cmdLogger.info("cmd={}|{}|client2proxy|from={}|to={}", RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), + ProxyConstants.PROTOCOL_HTTP, + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtil.getLocalAddress()); + + SendMessageRequestHeader sendMessageRequestHeader = (SendMessageRequestHeader) asyncContext.getRequest().getHeader(); + SendMessageRequestBody sendMessageRequestBody = (SendMessageRequestBody) asyncContext.getRequest().getBody(); + + SendMessageResponseHeader sendMessageResponseHeader = + SendMessageResponseHeader.buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), proxyHTTPServer.getProxyConfiguration().proxyCluster, + IPUtil.getLocalAddress(), proxyHTTPServer.getProxyConfiguration().proxyEnv, + proxyHTTPServer.getProxyConfiguration().proxyRegion, + proxyHTTPServer.getProxyConfiguration().proxyDCN, proxyHTTPServer.getProxyConfiguration().proxyIDC); + + //HEADER校验 + if (StringUtils.isBlank(sendMessageRequestHeader.getIdc()) + || StringUtils.isBlank(sendMessageRequestHeader.getDcn()) + || StringUtils.isBlank(sendMessageRequestHeader.getPid()) + || !StringUtils.isNumeric(sendMessageRequestHeader.getPid()) + || StringUtils.isBlank(sendMessageRequestHeader.getSys())) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + //BODY校验 + if (StringUtils.isBlank(sendMessageRequestBody.getBizSeqNo()) + || StringUtils.isBlank(sendMessageRequestBody.getUniqueId()) + || StringUtils.isBlank(sendMessageRequestBody.getTopic()) + || StringUtils.isBlank(sendMessageRequestBody.getContent()) + || (StringUtils.isBlank(sendMessageRequestBody.getTtl()))) { + //同步消息的TTL不能为空 + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + String producerGroup = ProxyUtil.buildClientGroup(sendMessageRequestHeader.getSys(), + sendMessageRequestHeader.getDcn()); + ProxyProducer proxyProducer = proxyHTTPServer.getProducerManager().getProxyProducer(producerGroup); + + if (!proxyProducer.getStarted().get()) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_GROUP_PRODUCER_STOPED_ERR.getRetCode(), ProxyRetCode.PROXY_GROUP_PRODUCER_STOPED_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + String ttl = String.valueOf(ProxyConstants.DEFAULT_MSG_TTL_MILLS); + if (StringUtils.isNotBlank(sendMessageRequestBody.getTtl()) && StringUtils.isNumeric(sendMessageRequestBody.getTtl())) { + ttl = sendMessageRequestBody.getTtl(); + } + + Message rocketMQMsg; + try { + if (StringUtils.isBlank(sendMessageRequestBody.getTag())) { + rocketMQMsg = new Message(sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getContent().getBytes(ProxyConstants.DEFAULT_CHARSET)); + } else { + rocketMQMsg = new Message(sendMessageRequestBody.getTopic(), sendMessageRequestBody.getTag(), + sendMessageRequestBody.getContent().getBytes(ProxyConstants.DEFAULT_CHARSET)); + } + + rocketMQMsg.putUserProperty(DeFiBusConstant.KEY, DeFiBusConstant.PERSISTENT); + rocketMQMsg.putUserProperty(DeFiBusConstant.PROPERTY_MESSAGE_TTL, ttl); + rocketMQMsg.putUserProperty(ProxyConstants.REQ_C2PROXY_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + rocketMQMsg.putUserProperty(Constants.RMB_UNIQ_ID, sendMessageRequestBody.getUniqueId()); + rocketMQMsg.setKeys(sendMessageRequestBody.getBizSeqNo()); + + if (messageLogger.isDebugEnabled()) { + messageLogger.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getTopic()); + } + rocketMQMsg.putUserProperty(ProxyConstants.REQ_PROXY2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + } catch (Exception e) { + messageLogger.error("msg2MQMsg err, bizSeqNo={}, topic={}", sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getTopic(), e); + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_PACKAGE_MSG_ERR.getRetCode(), ProxyRetCode.PROXY_PACKAGE_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(e, 2))); + asyncContext.onComplete(responseProxyCommand); + return; + } + + final SendMessageContext sendMessageContext = new SendMessageContext(sendMessageRequestBody.getBizSeqNo(), rocketMQMsg, proxyProducer, proxyHTTPServer); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsg(); + + long startTime = System.currentTimeMillis(); + + final CompleteHandler handler = new CompleteHandler() { + @Override + public void onResponse(HttpCommand httpCommand) { + try { + if (httpLogger.isDebugEnabled()) { + httpLogger.debug("{}", httpCommand); + } + proxyHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); + proxyHTTPServer.metrics.summaryMetrics.recordHTTPReqResTimeCost(System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); + } catch (Exception ex) { + } + } + }; + + LiteMessage liteMessage = new LiteMessage(sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getUniqueId(), sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getContent()) + .setProp(sendMessageRequestBody.getExtFields()); + + try { + sendMessageContext.getMsg().getProperties().put(ProxyConstants.REQ_PROXY2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + proxyProducer.send(sendMessageContext, new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + HttpCommand succ = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.SUCCESS.getRetCode(), ProxyRetCode.SUCCESS.getErrMsg() + sendResult.toString())); + asyncContext.onComplete(succ, handler); + long endTime = System.currentTimeMillis(); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsgCost(endTime - startTime); + messageLogger.info("message|proxy2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, + sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getUniqueId()); + } + + @Override + public void onException(Throwable e) { + HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_SEND_ASYNC_MSG_ERR.getRetCode(), + ProxyRetCode.PROXY_SEND_ASYNC_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(e, 2))); + asyncContext.onComplete(err, handler); + long endTime = System.currentTimeMillis(); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsgFailed(); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsgCost(endTime - startTime); + messageLogger.error("message|proxy2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, + sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getUniqueId(), e); + } + }); + } catch (Exception ex) { + HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_SEND_ASYNC_MSG_ERR.getRetCode(), + ProxyRetCode.PROXY_SEND_ASYNC_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(ex, 2))); + asyncContext.onComplete(err); + long endTime = System.currentTimeMillis(); + messageLogger.error("message|proxy2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, + sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getUniqueId(), ex); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsgFailed(); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsgCost(endTime - startTime); + } + + return; + } + + @Override + public boolean rejectRequest() { + return false; + } + +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SendSyncMessageProcessor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SendSyncMessageProcessor.java new file mode 100644 index 0000000000..b59cb248f6 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SendSyncMessageProcessor.java @@ -0,0 +1,306 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SendSyncMessageProcessor.java +package cn.webank.emesher.core.protocol.http.processor; + +import cn.webank.defibus.client.impl.producer.RRCallback; +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.emesher.core.protocol.http.async.CompleteHandler; +import cn.webank.emesher.core.protocol.http.processor.inf.HttpRequestProcessor; +import cn.webank.emesher.core.protocol.http.producer.ProxyProducer; +import cn.webank.emesher.core.protocol.http.producer.SendMessageContext; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.LiteMessage; +import cn.webank.eventmesh.common.command.HttpCommand; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import cn.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageRequestHeader; +import cn.webank.eventmesh.common.protocol.http.header.message.SendMessageResponseHeader; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.core.protocol.http.processor; + +import com.webank.defibus.client.impl.producer.RRCallback; +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.runtime.core.protocol.http.async.CompleteHandler; +import com.webank.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import com.webank.runtime.core.protocol.http.producer.ProxyProducer; +import com.webank.runtime.core.protocol.http.producer.SendMessageContext; +import com.webank.eventmesh.common.Constants; +import com.webank.eventmesh.common.IPUtil; +import com.webank.eventmesh.common.LiteMessage; +import com.webank.eventmesh.common.command.HttpCommand; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import com.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +import com.webank.eventmesh.common.protocol.http.header.message.SendMessageRequestHeader; +import com.webank.eventmesh.common.protocol.http.header.message.SendMessageResponseHeader; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/processor/SendSyncMessageProcessor.java +import com.alibaba.fastjson.JSON; +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SendSyncMessageProcessor implements HttpRequestProcessor { + + public Logger messageLogger = LoggerFactory.getLogger("message"); + + public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + + public Logger httpLogger = LoggerFactory.getLogger("http"); + + private ProxyHTTPServer proxyHTTPServer; + + public SendSyncMessageProcessor(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + @Override + public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { + + HttpCommand responseProxyCommand; + + cmdLogger.info("cmd={}|{}|client2proxy|from={}|to={}", RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), + ProxyConstants.PROTOCOL_HTTP, + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtil.getLocalAddress()); + + SendMessageRequestHeader sendMessageRequestHeader = (SendMessageRequestHeader) asyncContext.getRequest().getHeader(); + SendMessageRequestBody sendMessageRequestBody = (SendMessageRequestBody) asyncContext.getRequest().getBody(); + + SendMessageResponseHeader sendMessageResponseHeader = + SendMessageResponseHeader.buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), proxyHTTPServer.getProxyConfiguration().proxyCluster, + IPUtil.getLocalAddress(), proxyHTTPServer.getProxyConfiguration().proxyEnv, + proxyHTTPServer.getProxyConfiguration().proxyRegion, + proxyHTTPServer.getProxyConfiguration().proxyDCN, proxyHTTPServer.getProxyConfiguration().proxyIDC); + + if (StringUtils.isBlank(sendMessageRequestHeader.getIdc()) + || StringUtils.isBlank(sendMessageRequestHeader.getDcn()) + || StringUtils.isBlank(sendMessageRequestHeader.getPid()) + || !StringUtils.isNumeric(sendMessageRequestHeader.getPid()) + || StringUtils.isBlank(sendMessageRequestHeader.getSys())) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_HEADER_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + if (StringUtils.isBlank(sendMessageRequestBody.getBizSeqNo()) + || StringUtils.isBlank(sendMessageRequestBody.getUniqueId()) + || StringUtils.isBlank(sendMessageRequestBody.getTopic()) + || StringUtils.isBlank(sendMessageRequestBody.getContent()) + || (StringUtils.isBlank(sendMessageRequestBody.getTtl()))) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getRetCode(), ProxyRetCode.PROXY_PROTOCOL_BODY_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + String producerGroup = ProxyUtil.buildClientGroup(sendMessageRequestHeader.getSys(), + sendMessageRequestHeader.getDcn()); + ProxyProducer proxyProducer = proxyHTTPServer.getProducerManager().getProxyProducer(producerGroup); + + if (!proxyProducer.getStarted().get()) { + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_GROUP_PRODUCER_STOPED_ERR.getRetCode(), ProxyRetCode.PROXY_GROUP_PRODUCER_STOPED_ERR.getErrMsg())); + asyncContext.onComplete(responseProxyCommand); + return; + } + + String ttl = String.valueOf(ProxyConstants.DEFAULT_MSG_TTL_MILLS); + if (StringUtils.isNotBlank(sendMessageRequestBody.getTtl()) && StringUtils.isNumeric(sendMessageRequestBody.getTtl())) { + ttl = sendMessageRequestBody.getTtl(); + } + + Message rocketMQMsg; + try { + if (StringUtils.isBlank(sendMessageRequestBody.getTag())) { + rocketMQMsg = new Message(sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getContent().getBytes(ProxyConstants.DEFAULT_CHARSET)); + } else { + rocketMQMsg = new Message(sendMessageRequestBody.getTopic(), sendMessageRequestBody.getTag(), + sendMessageRequestBody.getContent().getBytes(ProxyConstants.DEFAULT_CHARSET)); + } + rocketMQMsg.putUserProperty(DeFiBusConstant.KEY, DeFiBusConstant.PERSISTENT); + rocketMQMsg.putUserProperty(DeFiBusConstant.PROPERTY_MESSAGE_TTL, ttl); + rocketMQMsg.putUserProperty(ProxyConstants.REQ_C2PROXY_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + rocketMQMsg.putUserProperty(Constants.RMB_UNIQ_ID, sendMessageRequestBody.getUniqueId()); + rocketMQMsg.setKeys(sendMessageRequestBody.getBizSeqNo()); + rocketMQMsg.putUserProperty(DeFiBusConstant.PROPERTY_MESSAGE_REPLY_TO, + proxyProducer.getDefibusProducer().getDefaultMQProducer().buildMQClientId()); + + if (messageLogger.isDebugEnabled()) { + messageLogger.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getTopic()); + } + rocketMQMsg.putUserProperty(ProxyConstants.REQ_PROXY2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + } catch (Exception e) { + messageLogger.error("msg2MQMsg err, bizSeqNo={}, topic={}", sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getTopic(), e); + responseProxyCommand = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_PACKAGE_MSG_ERR.getRetCode(), ProxyRetCode.PROXY_PACKAGE_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(e, 2))); + asyncContext.onComplete(responseProxyCommand); + return; + } + + final SendMessageContext sendMessageContext = new SendMessageContext(sendMessageRequestBody.getBizSeqNo(), rocketMQMsg, proxyProducer, proxyHTTPServer); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsg(); + + long startTime = System.currentTimeMillis(); + + final CompleteHandler handler = new CompleteHandler() { + @Override + public void onResponse(HttpCommand httpCommand) { + try { + if (httpLogger.isDebugEnabled()) { + httpLogger.debug("{}", httpCommand); + } + proxyHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); + proxyHTTPServer.metrics.summaryMetrics.recordHTTPReqResTimeCost(System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); + } catch (Exception ex) { + } + } + }; + + LiteMessage liteMessage = new LiteMessage(sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getUniqueId(), sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getContent()) + .setProp(sendMessageRequestBody.getExtFields()); + + try { + proxyProducer.request(sendMessageContext, new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + long endTime = System.currentTimeMillis(); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsgCost(endTime - startTime); + messageLogger.info("message|proxy2mq|REQ|SYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, + sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getUniqueId()); + } + + @Override + public void onException(Throwable e) { + HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_SEND_SYNC_MSG_ERR.getRetCode(), + ProxyRetCode.PROXY_SEND_SYNC_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(e, 2))); + asyncContext.onComplete(err, handler); + long endTime = System.currentTimeMillis(); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsgFailed(); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsgCost(endTime - startTime); + messageLogger.error("message|proxy2mq|REQ|SYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, + sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getUniqueId(), e); + } + }, new RRCallback() { + @Override + public void onSuccess(Message mqMsg) { + if (mqMsg instanceof MessageExt) { + mqMsg.putUserProperty(ProxyConstants.BORN_TIMESTAMP, String.valueOf(((MessageExt) mqMsg) + .getBornTimestamp())); + mqMsg.putUserProperty(ProxyConstants.STORE_TIMESTAMP, String.valueOf(((MessageExt) mqMsg) + .getStoreTimestamp())); + } + mqMsg.putUserProperty(ProxyConstants.RSP_MQ2PROXY_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + messageLogger.info("message|mq2proxy|RSP|SYNC|rrCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + System.currentTimeMillis() - startTime, + sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getUniqueId()); + + try { + final String rtnMsg = new String(mqMsg.getBody(), ProxyConstants.DEFAULT_CHARSET); + mqMsg.putUserProperty(ProxyConstants.RSP_PROXY2C_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + HttpCommand succ = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.SUCCESS.getRetCode(), + JSON.toJSONString(new SendMessageResponseBody.ReplyMessage(mqMsg.getTopic(), rtnMsg, + mqMsg.getProperties())))); + asyncContext.onComplete(succ, handler); + } catch (Exception ex) { + HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_WAITING_RR_MSG_ERR.getRetCode(), + ProxyRetCode.PROXY_WAITING_RR_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(ex, 2))); + asyncContext.onComplete(err, handler); + messageLogger.warn("message|mq2proxy|RSP", ex); + } + } + + @Override + public void onException(Throwable e) { + HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_WAITING_RR_MSG_ERR.getRetCode(), + ProxyRetCode.PROXY_WAITING_RR_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(e, 2))); + asyncContext.onComplete(err, handler); + messageLogger.error("message|mq2proxy|RSP|SYNC|rrCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + System.currentTimeMillis() - startTime, + sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getUniqueId(), e); + } + }, Integer.valueOf(ttl)); + } catch (Exception ex) { + HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(ProxyRetCode.PROXY_SEND_SYNC_MSG_ERR.getRetCode(), + ProxyRetCode.PROXY_SEND_SYNC_MSG_ERR.getErrMsg() + ProxyUtil.stackTrace(ex, 2))); + asyncContext.onComplete(err); + long endTime = System.currentTimeMillis(); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsgFailed(); + proxyHTTPServer.metrics.summaryMetrics.recordSendMsgCost(endTime - startTime); + messageLogger.error("message|proxy2mq|REQ|SYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, + sendMessageRequestBody.getTopic(), + sendMessageRequestBody.getBizSeqNo(), + sendMessageRequestBody.getUniqueId(), ex); + } + + return; + } + + @Override + public boolean rejectRequest() { + return false; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SubscribeProcessor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SubscribeProcessor.java new file mode 100644 index 0000000000..573d897cc7 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SubscribeProcessor.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/SubscribeProcessor.java +package cn.webank.emesher.core.protocol.http.processor; + +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.emesher.core.protocol.http.processor.inf.HttpRequestProcessor; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.command.HttpCommand; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +======== +package com.webank.runtime.core.protocol.http.processor; + +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import com.webank.eventmesh.common.IPUtil; +import com.webank.eventmesh.common.command.HttpCommand; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/processor/SubscribeProcessor.java +import io.netty.channel.ChannelHandlerContext; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SubscribeProcessor implements HttpRequestProcessor { + + public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + + private ProxyHTTPServer proxyHTTPServer; + + public SubscribeProcessor(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + @Override + public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { + + cmdLogger.info("cmd={}|{}|client2proxy|from={}|to={}", RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), + ProxyConstants.PROTOCOL_HTTP, + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtil.getLocalAddress()); + + } + + @Override + public boolean rejectRequest() { + return false; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/UnSubscribeProcessor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/UnSubscribeProcessor.java new file mode 100644 index 0000000000..c3f98ca491 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/UnSubscribeProcessor.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/UnSubscribeProcessor.java +package cn.webank.emesher.core.protocol.http.processor; + +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.emesher.core.protocol.http.processor.inf.HttpRequestProcessor; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.command.HttpCommand; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +======== +package com.webank.runtime.core.protocol.http.processor; + +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import com.webank.eventmesh.common.IPUtil; +import com.webank.eventmesh.common.command.HttpCommand; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/processor/UnSubscribeProcessor.java +import io.netty.channel.ChannelHandlerContext; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UnSubscribeProcessor implements HttpRequestProcessor { + + public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + + private ProxyHTTPServer proxyHTTPServer; + + public UnSubscribeProcessor(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + @Override + public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { + + cmdLogger.info("cmd={}|{}|client2proxy|from={}|to={}", RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), + ProxyConstants.PROTOCOL_HTTP, + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtil.getLocalAddress()); + + } + + @Override + public boolean rejectRequest() { + return false; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/inf/HttpRequestProcessor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/inf/HttpRequestProcessor.java new file mode 100644 index 0000000000..42e09e988d --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/inf/HttpRequestProcessor.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/processor/inf/HttpRequestProcessor.java +package cn.webank.emesher.core.protocol.http.processor.inf; + +import cn.webank.emesher.core.protocol.http.async.AsyncContext; +import cn.webank.eventmesh.common.command.HttpCommand; +======== +package com.webank.runtime.core.protocol.http.processor.inf; + +import com.webank.runtime.core.protocol.http.async.AsyncContext; +import com.webank.eventmesh.common.command.HttpCommand; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/processor/inf/HttpRequestProcessor.java +import io.netty.channel.ChannelHandlerContext; + +public interface HttpRequestProcessor { + + void processRequest(final ChannelHandlerContext ctx, final AsyncContext asyncContext) + throws Exception; + + boolean rejectRequest(); + +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/ProducerManager.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/ProducerManager.java new file mode 100644 index 0000000000..352aa3ff67 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/ProducerManager.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/ProducerManager.java +package cn.webank.emesher.core.protocol.http.producer; + +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.core.consumergroup.ProducerGroupConf; +======== +package com.webank.runtime.core.protocol.http.producer; + +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.core.consumergroup.ProducerGroupConf; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/producer/ProducerManager.java +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.ConcurrentHashMap; + +public class ProducerManager { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + private ProxyHTTPServer proxyHTTPServer; + + private ConcurrentHashMap producerTable = new ConcurrentHashMap(); + + public ProducerManager(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + public void init() throws Exception { + logger.info("producerManager inited......"); + } + + public void start() throws Exception { + logger.info("producerManager started......"); + } + + public ProxyProducer getProxyProducer(String producerGroup) throws Exception { + ProxyProducer proxyProducer = null; + if (!producerTable.containsKey(producerGroup)) { + synchronized (producerTable) { + if (!producerTable.containsKey(producerGroup)) { + ProducerGroupConf producerGroupConfig = new ProducerGroupConf(producerGroup); + proxyProducer = createProxyProducer(producerGroupConfig); + proxyProducer.start(); + } + } + } + + proxyProducer = producerTable.get(producerGroup); + + if (!proxyProducer.getStarted().get()) { + proxyProducer.start(); + } + + return proxyProducer; + } + + public synchronized ProxyProducer createProxyProducer(ProducerGroupConf producerGroupConfig) throws Exception { + if (producerTable.containsKey(producerGroupConfig.getGroupName())) { + return producerTable.get(producerGroupConfig.getGroupName()); + } + ProxyProducer proxyProducer = new ProxyProducer(); + proxyProducer.init(proxyHTTPServer.getProxyConfiguration(), producerGroupConfig); + producerTable.put(producerGroupConfig.getGroupName(), proxyProducer); + return proxyProducer; + } + + public void shutdown() { + for (ProxyProducer proxyProducer : producerTable.values()) { + try { + proxyProducer.shutdown(); + } catch (Exception ex) { + logger.error("shutdown proxyProducer[{}] err", proxyProducer, ex); + } + } + logger.info("producerManager shutdown......"); + } + + public ProxyHTTPServer getProxyHTTPServer() { + return proxyHTTPServer; + } + + public ConcurrentHashMap getProducerTable() { + return producerTable; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/ProxyProducer.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/ProxyProducer.java new file mode 100644 index 0000000000..203f45fdc9 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/ProxyProducer.java @@ -0,0 +1,154 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/ProxyProducer.java +package cn.webank.emesher.core.protocol.http.producer; + +import cn.webank.defibus.client.common.DeFiBusClientConfig; +import cn.webank.defibus.client.impl.producer.RRCallback; +import cn.webank.defibus.producer.DeFiBusProducer; +import cn.webank.emesher.configuration.ProxyConfiguration; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.consumergroup.ProducerGroupConf; +import cn.webank.eventmesh.common.ThreadUtil; +import cn.webank.emesher.util.ProxyUtil; +import org.apache.commons.lang3.StringUtils; +======== +package com.webank.runtime.core.protocol.http.producer; + +import com.webank.defibus.client.impl.producer.RRCallback; +import com.webank.runtime.configuration.ProxyConfiguration; +import com.webank.runtime.core.consumergroup.ProducerGroupConf; +import com.webank.runtime.core.plugin.MQProducerWrapper; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/producer/ProxyProducer.java +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class ProxyProducer { + + protected AtomicBoolean started = new AtomicBoolean(Boolean.FALSE); + + protected AtomicBoolean inited = new AtomicBoolean(Boolean.FALSE); + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public AtomicBoolean getInited() { + return inited; + } + + public AtomicBoolean getStarted() { + return started; + } + + protected ProducerGroupConf producerGroupConfig; + + protected ProxyConfiguration proxyConfiguration; + + public void send(SendMessageContext sendMsgContext, SendCallback sendCallback) throws Exception { + defibusProducer.publish(sendMsgContext.getMsg(), sendCallback); + } + + public void request(SendMessageContext sendMsgContext, SendCallback sendCallback, RRCallback rrCallback, long timeout) + throws InterruptedException, RemotingException, MQClientException, MQBrokerException { + defibusProducer.request(sendMsgContext.getMsg(), sendCallback, rrCallback, timeout); + } + + public Message request(SendMessageContext sendMessageContext, long timeout) throws InterruptedException, RemotingException, MQClientException, MQBrokerException { + return defibusProducer.request(sendMessageContext.getMsg(), timeout); + } + + public boolean reply(final SendMessageContext sendMsgContext, final SendCallback sendCallback) throws Exception { + defibusProducer.reply(sendMsgContext.getMsg(), sendCallback); + return true; + } + + protected DeFiBusProducer defibusProducer; + + public DeFiBusProducer getDefibusProducer() { + return defibusProducer; + } + + public synchronized void init(ProxyConfiguration proxyConfiguration, ProducerGroupConf producerGroupConfig) { + this.producerGroupConfig = producerGroupConfig; + this.proxyConfiguration = proxyConfiguration; + DeFiBusClientConfig wcc = new DeFiBusClientConfig(); + wcc.setClusterPrefix(proxyConfiguration.proxyIDC); + wcc.setPollNameServerInterval(proxyConfiguration.pollNameServerInteval); + wcc.setHeartbeatBrokerInterval(proxyConfiguration.heartbeatBrokerInterval); + wcc.setProducerGroup(ProxyConstants.PRODUCER_GROUP_NAME_PREFIX + producerGroupConfig.getGroupName()); + + if (StringUtils.isEmpty(proxyConfiguration.namesrvAddr)) { + wcc.setWsAddr(ProxyUtil.buildCCAddr(proxyConfiguration.configCenterAddr, proxyConfiguration.proxyIDC)); + } else { + wcc.setNamesrvAddr(proxyConfiguration.namesrvAddr); + } + + MessageClientIDSetter.createUniqID(); + defibusProducer = new DeFiBusProducer(wcc); + inited.compareAndSet(false, true); + logger.info("ProxyProducer [{}] inited.............", producerGroupConfig.getGroupName()); + } + + + public synchronized void start() throws Exception { + if (started.get()) { + return; + } + defibusProducer.getDefaultMQProducer().setVipChannelEnabled(false); + defibusProducer.getDefaultMQProducer().setInstanceName(ProxyUtil.buildProxyClientID(producerGroupConfig.getGroupName(), + proxyConfiguration.proxyRegion, proxyConfiguration.proxyCluster)); + defibusProducer.getDefaultMQProducer().setCompressMsgBodyOverHowmuch(2 * 1024); + defibusProducer.start(); + started.compareAndSet(false, true); + ThreadUtil.randomSleep(500); + defibusProducer.getDefaultMQProducer().getDefaultMQProducerImpl().getmQClientFactory().updateTopicRouteInfoFromNameServer(); + logger.info("ProxyProducer [{}] started.............", producerGroupConfig.getGroupName()); + } + + public synchronized void shutdown() throws Exception { + if (!inited.get()) { + return; + } + + if (!started.get()) { + return; + } + defibusProducer.shutdown(); + inited.compareAndSet(true, false); + started.compareAndSet(true, false); + logger.info("ProxyProducer [{}] shutdown.............", producerGroupConfig.getGroupName()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("proxyProducer={") + .append("inited=").append(inited.get()).append(",") + .append("started=").append(started.get()).append(",") + .append("producerGroupConfig=").append(producerGroupConfig).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/SendMessageContext.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/SendMessageContext.java new file mode 100644 index 0000000000..9b3faaf4f9 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/SendMessageContext.java @@ -0,0 +1,145 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/producer/SendMessageContext.java +package cn.webank.emesher.core.protocol.http.producer; + +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.core.protocol.http.retry.RetryContext; +import cn.webank.eventmesh.common.Constants; +======== +package com.webank.runtime.core.protocol.http.producer; + +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.core.protocol.http.retry.RetryContext; +import com.webank.eventmesh.common.Constants; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/producer/SendMessageContext.java +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +public class SendMessageContext extends RetryContext { + + public static Logger logger = LoggerFactory.getLogger("retry"); + + private Message msg; + + private String bizSeqNo; + + private ProxyProducer proxyProducer; + + private long createTime = System.currentTimeMillis(); + + private Map props; + + public ProxyHTTPServer proxyHTTPServer; + + public SendMessageContext(String bizSeqNo, Message msg, ProxyProducer proxyProducer, ProxyHTTPServer proxyHTTPServer) { + this.bizSeqNo = bizSeqNo; + this.msg = msg; + this.proxyProducer = proxyProducer; + this.proxyHTTPServer = proxyHTTPServer; + } + + public void addProp(String key, String val) { + if (props == null) { + props = new HashMap<>(); + } + props.put(key, val); + } + + public String getProp(String key) { + return props.get(key); + } + + public String getBizSeqNo() { + return bizSeqNo; + } + + public void setBizSeqNo(String bizSeqNo) { + this.bizSeqNo = bizSeqNo; + } + + public Message getMsg() { + return msg; + } + + public void setMsg(Message msg) { + this.msg = msg; + } + + public ProxyProducer getProxyProducer() { + return proxyProducer; + } + + public void setProxyProducer(ProxyProducer proxyProducer) { + this.proxyProducer = proxyProducer; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageContext={") + .append("bizSeqNo=").append(bizSeqNo) + .append(",retryTimes=").append(retryTimes) + .append(",producer=").append(proxyProducer != null ? proxyProducer.producerGroupConfig.getGroupName() : null) + .append(",executeTime=").append(DateFormatUtils.format(executeTime, Constants.DATE_FORMAT)) + .append(",createTime=").append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + @Override + public boolean retry() throws Exception { + if (proxyProducer == null) { + return false; + } + + if (retryTimes > 0) { //只给一次重试机会 + return false; + } + + retryTimes++; + proxyProducer.send(this, new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + + } + + @Override + public void onException(Throwable e) { + logger.warn("", e); + proxyHTTPServer.metrics.summaryMetrics.recordSendBatchMsgFailed(1); + } + }); + + return true; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/AbstractHTTPPushRequest.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/AbstractHTTPPushRequest.java new file mode 100644 index 0000000000..a08ef872b5 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/AbstractHTTPPushRequest.java @@ -0,0 +1,129 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/AbstractHTTPPushRequest.java +package cn.webank.emesher.core.protocol.http.push; + +import cn.webank.emesher.boot.ProxyHTTPServer; +import cn.webank.emesher.configuration.ProxyConfiguration; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.consumer.HandleMsgContext; +import cn.webank.emesher.core.protocol.http.retry.HttpRetryer; +import cn.webank.emesher.core.protocol.http.retry.RetryContext; +======== +package com.webank.runtime.core.protocol.http.push; + +import com.webank.runtime.boot.ProxyHTTPServer; +import com.webank.runtime.configuration.ProxyConfiguration; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.consumer.HandleMsgContext; +import com.webank.runtime.core.protocol.http.retry.HttpRetryer; +import com.webank.runtime.core.protocol.http.retry.RetryContext; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/push/AbstractHTTPPushRequest.java +import com.google.common.collect.Lists; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.RandomUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +public abstract class AbstractHTTPPushRequest extends RetryContext { + + public ProxyHTTPServer proxyHTTPServer; + + public long createTime = System.currentTimeMillis(); + + public long lastPushTime = System.currentTimeMillis(); + + public Map> urls; + + public List totalUrls; + + public volatile int startIdx; + + public ProxyConfiguration proxyConfiguration; + + public HttpRetryer retryer; + + public int ttl; + + public HandleMsgContext handleMsgContext; + + public static HTTPClientPool httpClientPool = new HTTPClientPool(10); + + private AtomicBoolean complete = new AtomicBoolean(Boolean.FALSE); + + public AbstractHTTPPushRequest(HandleMsgContext handleMsgContext) { + this.proxyHTTPServer = handleMsgContext.getProxyHTTPServer(); + this.handleMsgContext = handleMsgContext; + this.urls = handleMsgContext.getConsumeTopicConfig().getIdcUrls(); + this.totalUrls = Lists.newArrayList(handleMsgContext.getConsumeTopicConfig().getUrls()); + this.proxyConfiguration = handleMsgContext.getProxyHTTPServer().getProxyConfiguration(); + this.retryer = handleMsgContext.getProxyHTTPServer().getHttpRetryer(); + this.ttl = handleMsgContext.getTtl(); + this.startIdx = RandomUtils.nextInt(0, totalUrls.size()); + } + + public void tryHTTPRequest() { + } + + public void delayRetry() { + if (retryTimes < ProxyConstants.DEFAULT_PUSH_RETRY_TIMES) { + retryTimes++; + delay(retryTimes * ProxyConstants.DEFAULT_PUSH_RETRY_TIME_DISTANCE_IN_MILLSECONDS); + retryer.pushRetry(this); + } else { + complete.compareAndSet(Boolean.FALSE, Boolean.TRUE); + } + } + + public String getUrl() { + List localIDCUrl = MapUtils.getObject(urls, + proxyConfiguration.proxyIDC, null); + if (CollectionUtils.isNotEmpty(localIDCUrl)) { + return localIDCUrl.get((startIdx + retryTimes) % localIDCUrl.size()); + } + + List otherIDCUrl = new ArrayList(); + for (List tmp : urls.values()) { + otherIDCUrl.addAll(tmp); + } + + if (CollectionUtils.isNotEmpty(otherIDCUrl)) { + return otherIDCUrl.get((startIdx + retryTimes) % otherIDCUrl.size()); + } + + return null; + } + + public boolean isComplete() { + return complete.get(); + } + + public void complete() { + complete.compareAndSet(Boolean.FALSE, Boolean.TRUE); + } + + public void timeout() { + if (!isComplete() && System.currentTimeMillis() - lastPushTime >= ttl) { + delayRetry(); + } + } +} \ No newline at end of file diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/AsyncHTTPPushRequest.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/AsyncHTTPPushRequest.java new file mode 100644 index 0000000000..7f9b88b8fe --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/AsyncHTTPPushRequest.java @@ -0,0 +1,289 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/AsyncHTTPPushRequest.java +package cn.webank.emesher.core.protocol.http.push; + +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.http.consumer.HandleMsgContext; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.protocol.http.body.message.PushMessageRequestBody; +import cn.webank.eventmesh.common.protocol.http.common.ClientRetCode; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.core.protocol.http.push; + +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.http.consumer.HandleMsgContext; +import com.webank.eventmesh.common.Constants; +import com.webank.eventmesh.common.IPUtil; +import com.webank.eventmesh.common.protocol.http.body.message.PushMessageRequestBody; +import com.webank.eventmesh.common.protocol.http.common.ClientRetCode; +import com.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import com.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/push/AsyncHTTPPushRequest.java +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Sets; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class AsyncHTTPPushRequest extends AbstractHTTPPushRequest { + + public Logger messageLogger = LoggerFactory.getLogger("message"); + + public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + private Map> waitingRequests; + + public String currPushUrl; + + public AsyncHTTPPushRequest(HandleMsgContext handleMsgContext, Map> waitingRequests) { + super(handleMsgContext); + this.waitingRequests = waitingRequests; + } + + public void tryHTTPRequest() { + + currPushUrl = getUrl(); + + if (StringUtils.isBlank(currPushUrl)) { + return; + } + + HttpPost builder = new HttpPost(currPushUrl); + + String requestCode = ""; + + if (ProxyUtil.isService(handleMsgContext.getTopic())) { + requestCode = String.valueOf(RequestCode.HTTP_PUSH_CLIENT_SYNC.getRequestCode()); + } else { + requestCode = String.valueOf(RequestCode.HTTP_PUSH_CLIENT_ASYNC.getRequestCode()); + } + + builder.addHeader(ProtocolKey.REQUEST_CODE, requestCode); + builder.addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA); + builder.addHeader(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()); + builder.addHeader(ProtocolKey.ProxyInstanceKey.PROXYCLUSTER, handleMsgContext.getProxyHTTPServer().getProxyConfiguration().proxyCluster); + builder.addHeader(ProtocolKey.ProxyInstanceKey.PROXYIP, IPUtil.getLocalAddress()); + builder.addHeader(ProtocolKey.ProxyInstanceKey.PROXYDCN, handleMsgContext.getProxyHTTPServer().getProxyConfiguration().proxyDCN); + builder.addHeader(ProtocolKey.ProxyInstanceKey.PROXYENV, handleMsgContext.getProxyHTTPServer().getProxyConfiguration().proxyEnv); + builder.addHeader(ProtocolKey.ProxyInstanceKey.PROXYREGION, handleMsgContext.getProxyHTTPServer().getProxyConfiguration().proxyRegion); + builder.addHeader(ProtocolKey.ProxyInstanceKey.PROXYIDC, handleMsgContext.getProxyHTTPServer().getProxyConfiguration().proxyIDC); + + handleMsgContext.getMsg().putUserProperty(ProxyConstants.REQ_PROXY2C_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + + String content = ""; + try { + content = new String(handleMsgContext.getMsg().getBody(), ProxyConstants.DEFAULT_CHARSET); + } catch (Exception ex) { + return; + } + + List body = new ArrayList(); + body.add(new BasicNameValuePair(PushMessageRequestBody.CONTENT, content)); + if (StringUtils.isBlank(handleMsgContext.getBizSeqNo())) { + body.add(new BasicNameValuePair(PushMessageRequestBody.BIZSEQNO, RandomStringUtils.randomNumeric(20))); + } else { + body.add(new BasicNameValuePair(PushMessageRequestBody.BIZSEQNO, handleMsgContext.getBizSeqNo())); + } + if (StringUtils.isBlank(handleMsgContext.getUniqueId())) { + body.add(new BasicNameValuePair(PushMessageRequestBody.UNIQUEID, RandomStringUtils.randomNumeric(20))); + } else { + body.add(new BasicNameValuePair(PushMessageRequestBody.UNIQUEID, handleMsgContext.getUniqueId())); + } + + body.add(new BasicNameValuePair(PushMessageRequestBody.RANDOMNO, handleMsgContext.getMsgRandomNo())); + body.add(new BasicNameValuePair(PushMessageRequestBody.TOPIC, handleMsgContext.getTopic())); + + body.add(new BasicNameValuePair(PushMessageRequestBody.EXTFIELDS, JSON.toJSONString(handleMsgContext.getMsg().getProperties()))); + + try { + builder.setEntity(new UrlEncodedFormEntity(body)); + } catch (UnsupportedEncodingException e) { + return; + } + + proxyHTTPServer.metrics.summaryMetrics.recordPushMsg(); + + this.lastPushTime = System.currentTimeMillis(); + + addToWaitingMap(this); + + cmdLogger.info("cmd={}|proxy2client|from={}|to={}", requestCode, + IPUtil.getLocalAddress(), currPushUrl); + + try { + httpClientPool.getClient().execute(builder, new ResponseHandler() { + @Override + public Object handleResponse(HttpResponse response) { + removeWaitingMap(AsyncHTTPPushRequest.this); + long cost = System.currentTimeMillis() - lastPushTime; + proxyHTTPServer.metrics.summaryMetrics.recordHTTPPushTimeCost(cost); + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + proxyHTTPServer.metrics.summaryMetrics.recordHttpPushMsgFailed(); + messageLogger.info("message|proxy2client|exception|url={}|topic={}|bizSeqNo={}|uniqueId={}|cost={}", currPushUrl, handleMsgContext.getTopic(), + handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), cost); + + delayRetry(); + if (isComplete()) { + handleMsgContext.finish(); + } + } else { + String res = ""; + try { + res = EntityUtils.toString(response.getEntity(), Charset.forName(ProxyConstants.DEFAULT_CHARSET)); + } catch (IOException e) { + handleMsgContext.finish(); + return new Object(); + } + ClientRetCode result = processResponseContent(res); + messageLogger.info("message|proxy2client|{}|url={}|topic={}|bizSeqNo={}|uniqueId={}|cost={}", result, currPushUrl, handleMsgContext.getTopic(), + handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), cost); + if (result == ClientRetCode.OK) { + complete(); + if (isComplete()) { + handleMsgContext.finish(); + } + } else if (result == ClientRetCode.RETRY) { + delayRetry(); + if (isComplete()) { + handleMsgContext.finish(); + } + } else if (result == ClientRetCode.NOLISTEN) { + delayRetry(); + if (isComplete()) { + handleMsgContext.finish(); + } + } else if (result == ClientRetCode.FAIL) { + complete(); + if (isComplete()) { + handleMsgContext.finish(); + } + } + } + return new Object(); + } + }); + + if (messageLogger.isDebugEnabled()) { + messageLogger.debug("message|proxy2client|url={}|topic={}|msg={}", currPushUrl, handleMsgContext.getTopic(), + handleMsgContext.getMsg()); + } else { + messageLogger.info("message|proxy2client|url={}|topic={}|bizSeqNo={}|uniqueId={}", currPushUrl, handleMsgContext.getTopic(), + handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId()); + } + } catch (IOException e) { + messageLogger.error("push2client err", e); + removeWaitingMap(this); + delayRetry(); + if (isComplete()) { + handleMsgContext.finish(); + } + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("asyncPushRequest={") + .append("bizSeqNo=").append(handleMsgContext.getBizSeqNo()) + .append(",startIdx=").append(startIdx) + .append(",retryTimes=").append(retryTimes) + .append(",uniqueId=").append(handleMsgContext.getUniqueId()) + .append(",executeTime=").append(DateFormatUtils.format(executeTime, Constants.DATE_FORMAT)) + .append(",lastPushTime=").append(DateFormatUtils.format(lastPushTime, Constants.DATE_FORMAT)) + .append(",createTime=").append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT)).append("}"); + return sb.toString(); + } + + ClientRetCode processResponseContent(String content) { + if (StringUtils.isBlank(content)) { + return ClientRetCode.FAIL; + } + + try { + JSONObject ret = JSONObject.parseObject(content); + Integer retCode = ret.getInteger("retCode"); + if (retCode != null && ClientRetCode.contains(retCode)) { + return ClientRetCode.get(retCode); + } + + return ClientRetCode.FAIL; + } catch (NumberFormatException e) { + messageLogger.warn("url:{}, bizSeqno:{}, uniqueId:{}, httpResponse:{}", currPushUrl, handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), content); + return ClientRetCode.FAIL; + } catch (JSONException e) { + messageLogger.warn("url:{}, bizSeqno:{}, uniqueId:{}, httpResponse:{}", currPushUrl, handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), content); + return ClientRetCode.FAIL; + } catch (Throwable t) { + messageLogger.warn("url:{}, bizSeqno:{}, uniqueId:{}, httpResponse:{}", currPushUrl, handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), content); + return ClientRetCode.FAIL; + } + } + + private void addToWaitingMap(AsyncHTTPPushRequest request) { + if (waitingRequests.containsKey(request.handleMsgContext.getConsumerGroup())) { + waitingRequests.get(request.handleMsgContext.getConsumerGroup()).add(request); + return; + } + waitingRequests.put(request.handleMsgContext.getConsumerGroup(), Sets.newConcurrentHashSet()); + waitingRequests.get(request.handleMsgContext.getConsumerGroup()).add(request); + return; + } + + private void removeWaitingMap(AsyncHTTPPushRequest request) { + if (waitingRequests.containsKey(request.handleMsgContext.getConsumerGroup())) { + waitingRequests.get(request.handleMsgContext.getConsumerGroup()).remove(request); + return; + } + } + + @Override + public boolean retry() { + tryHTTPRequest(); + return true; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/HTTPClientPool.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/HTTPClientPool.java new file mode 100644 index 0000000000..78cdd70a34 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/HTTPClientPool.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/HTTPClientPool.java +package cn.webank.emesher.core.protocol.http.push; +======== +package com.webank.runtime.core.protocol.http.push; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/push/HTTPClientPool.java + +import com.google.common.collect.Lists; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.RandomUtils; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; + +import java.util.Iterator; +import java.util.List; + +public class HTTPClientPool { + + private List clients = Lists.newArrayList(); + + private int core = 1; + + public HTTPClientPool(int core) { + this.core = core; + } + + public CloseableHttpClient getClient() { + if (CollectionUtils.size(clients) < core) { + CloseableHttpClient client = HttpClients.createDefault(); + clients.add(client); + return client; + } + return clients.get(RandomUtils.nextInt(core, 2 * core) % core); + } + + + public void shutdown() throws Exception { + Iterator itr = clients.iterator(); + while (itr.hasNext()) { + CloseableHttpClient client = itr.next(); + client.close(); + itr.remove(); + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/HTTPMessageHandler.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/HTTPMessageHandler.java new file mode 100644 index 0000000000..1472a4efeb --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/HTTPMessageHandler.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/HTTPMessageHandler.java +package cn.webank.emesher.core.protocol.http.push; + +import cn.webank.emesher.core.protocol.http.consumer.HandleMsgContext; +import cn.webank.emesher.core.protocol.http.consumer.ProxyConsumer; +import cn.webank.eventmesh.common.ThreadPoolFactory; +======== +package com.webank.runtime.core.protocol.http.push; + +import com.webank.runtime.core.protocol.http.consumer.HandleMsgContext; +import com.webank.runtime.core.protocol.http.consumer.ProxyConsumer; +import com.webank.eventmesh.common.ThreadPoolFactory; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/push/HTTPMessageHandler.java +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.apache.commons.collections4.MapUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class HTTPMessageHandler implements MessageHandler { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + private ProxyConsumer proxyConsumer; + + private static final ScheduledExecutorService SCHEDULER = ThreadPoolFactory.createSingleScheduledExecutor("proxy-pushMsgTimeout-"); + + private ThreadPoolExecutor pushExecutor; + + private final Integer CONSUMER_GROUP_WAITING_REQUEST_THRESHOLD = 10000; + + private void checkTimeout() { + waitingRequests.entrySet().stream().forEach(entry -> { + for (AbstractHTTPPushRequest request : entry.getValue()) { + request.timeout(); + waitingRequests.get(request.handleMsgContext.getConsumerGroup()).remove(request); + } + }); + } + + public static Map> waitingRequests = Maps.newConcurrentMap(); + + public HTTPMessageHandler(ProxyConsumer proxyConsumer) { + this.proxyConsumer = proxyConsumer; + this.pushExecutor = proxyConsumer.getProxyHTTPServer().pushMsgExecutor; + waitingRequests.put(this.proxyConsumer.getConsumerGroupConf().getConsumerGroup(), Sets.newConcurrentHashSet()); + SCHEDULER.scheduleAtFixedRate(this::checkTimeout, 0, 1000, TimeUnit.MILLISECONDS); + } + + @Override + public boolean handle(final HandleMsgContext handleMsgContext) { + Set waitingRequests4Group = MapUtils.getObject(waitingRequests, + handleMsgContext.getConsumerGroup(), Sets.newConcurrentHashSet()); + if (waitingRequests4Group.size() > CONSUMER_GROUP_WAITING_REQUEST_THRESHOLD) { + logger.warn("waitingRequests is too many, so reject, this message will be send back to MQ, consumerGroup:{}, threshold:{}", + handleMsgContext.getConsumerGroup(), CONSUMER_GROUP_WAITING_REQUEST_THRESHOLD); + return false; + } + + try { + pushExecutor.submit(() -> { + AsyncHTTPPushRequest asyncPushRequest = new AsyncHTTPPushRequest(handleMsgContext, waitingRequests); + asyncPushRequest.tryHTTPRequest(); + }); + return true; + } catch (RejectedExecutionException e) { + logger.warn("pushMsgThreadPoolQueue is full, so reject, current task size {}", handleMsgContext.getProxyHTTPServer().getPushMsgExecutor().getQueue().size(), e); + return false; + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/MessageHandler.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/MessageHandler.java new file mode 100644 index 0000000000..a4189be18e --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/MessageHandler.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/push/MessageHandler.java +package cn.webank.emesher.core.protocol.http.push; + +import cn.webank.emesher.core.protocol.http.consumer.HandleMsgContext; +======== +package com.webank.runtime.core.protocol.http.push; + +import com.webank.runtime.core.protocol.http.consumer.HandleMsgContext; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/push/MessageHandler.java + +public interface MessageHandler { + boolean handle(HandleMsgContext handleMsgContext); +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/DelayRetryable.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/DelayRetryable.java new file mode 100644 index 0000000000..c7c03e7471 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/DelayRetryable.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/DelayRetryable.java +package cn.webank.emesher.core.protocol.http.retry; +======== +package com.webank.runtime.core.protocol.http.retry; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/retry/DelayRetryable.java + +import java.util.concurrent.Delayed; + +public interface DelayRetryable extends Delayed { + boolean retry() throws Exception; +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/HttpRetryer.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/HttpRetryer.java new file mode 100644 index 0000000000..1882b96477 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/HttpRetryer.java @@ -0,0 +1,121 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/HttpRetryer.java +package cn.webank.emesher.core.protocol.http.retry; + +import cn.webank.emesher.boot.ProxyHTTPServer; +======== +package com.webank.runtime.core.protocol.http.retry; + +import com.webank.runtime.boot.ProxyHTTPServer; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/retry/HttpRetryer.java +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class HttpRetryer { + + private Logger retryLogger = LoggerFactory.getLogger("retry"); + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + private ProxyHTTPServer proxyHTTPServer; + + public HttpRetryer(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + private DelayQueue failed = new DelayQueue(); + + private ThreadPoolExecutor pool; + + private Thread dispatcher; + + public void pushRetry(DelayRetryable delayRetryable) { + if (failed.size() >= proxyHTTPServer.getProxyConfiguration().proxyServerRetryBlockQSize) { + retryLogger.error("[RETRY-QUEUE] is full!"); + return; + } + failed.offer(delayRetryable); + } + + public void init() { + pool = new ThreadPoolExecutor(proxyHTTPServer.getProxyConfiguration().proxyServerRetryThreadNum, + proxyHTTPServer.getProxyConfiguration().proxyServerRetryThreadNum, + 60000, + TimeUnit.MILLISECONDS, new ArrayBlockingQueue(proxyHTTPServer.getProxyConfiguration().proxyServerRetryBlockQSize), + new ThreadFactory() { + private AtomicInteger ai = new AtomicInteger(); + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r, "http-retry-" + ai.incrementAndGet()); + thread.setPriority(Thread.NORM_PRIORITY); + thread.setDaemon(true); + return thread; + } + }, new ThreadPoolExecutor.AbortPolicy()); + + dispatcher = new Thread(new Runnable() { + @Override + public void run() { + try { + DelayRetryable retryObj = null; + while (!Thread.currentThread().isInterrupted() && (retryObj = failed.take()) != null) { + final DelayRetryable delayRetryable = retryObj; + pool.execute(() -> { + try { + delayRetryable.retry(); + if(retryLogger.isDebugEnabled()) { + retryLogger.debug("retryObj : {}", delayRetryable); + } + } catch (Exception e) { + retryLogger.error("http-retry-dispatcher error!", e); + } + }); + } + } catch (Exception e) { + retryLogger.error("http-retry-dispatcher error!", e); + } + } + }, "http-retry-dispatcher"); + dispatcher.setDaemon(true); + logger.info("HttpRetryer inited......"); + } + + public int size() { + return failed.size(); + } + + public void shutdown() { + dispatcher.interrupt(); + pool.shutdown(); + logger.info("HttpRetryer shutdown......"); + } + + public void start() throws Exception { + dispatcher.start(); + logger.info("HttpRetryer started......"); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/RetryContext.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/RetryContext.java new file mode 100644 index 0000000000..3e9483daef --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/RetryContext.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/http/retry/RetryContext.java +package cn.webank.emesher.core.protocol.http.retry; +======== +package com.webank.runtime.core.protocol.http.retry; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/http/retry/RetryContext.java + +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +public abstract class RetryContext implements DelayRetryable { + + public int retryTimes = 0; + + public long executeTime = System.currentTimeMillis(); + + public RetryContext delay(long delay) { + this.executeTime = System.currentTimeMillis() + delay; + return this; + } + + @Override + public int compareTo(Delayed delayed) { + RetryContext obj = (RetryContext) delayed; + if (this.executeTime > obj.executeTime) { + return 1; + } else if (this.executeTime == obj.executeTime) { + return 0; + } else { + return -1; + } + } + + @Override + public long getDelay(TimeUnit unit) { + return unit.convert(this.executeTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcp2Client.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcp2Client.java new file mode 100644 index 0000000000..3da2f5d20b --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcp2Client.java @@ -0,0 +1,176 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcp2Client.java +package cn.webank.emesher.core.protocol.tcp.client; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.emesher.core.protocol.tcp.client.session.SessionState; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.RedirectInfo; +import cn.webank.emesher.metrics.tcp.ProxyTcpMonitor; +import cn.webank.emesher.util.Utils; +======== +package com.webank.runtime.core.protocol.tcp.client; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.runtime.core.protocol.tcp.client.session.SessionState; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.eventmesh.common.protocol.tcp.RedirectInfo; +import com.webank.runtime.metrics.tcp.ProxyTcpMonitor; +import com.webank.runtime.util.Utils; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/ProxyTcp2Client.java +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; + +import static cn.webank.eventmesh.common.protocol.tcp.Command.REDIRECT_TO_CLIENT; +import static cn.webank.eventmesh.common.protocol.tcp.Command.SERVER_GOODBYE_REQUEST; + +public class ProxyTcp2Client { + + private static final Logger logger = LoggerFactory.getLogger(ProxyTcp2Client.class); + + public static InetSocketAddress serverGoodby2Client(Session session, ClientSessionGroupMapping mapping) { + logger.info("serverGoodby2Client client[{}]", session.getClient()); + try{ + long startTime = System.currentTimeMillis(); + Package msg = new Package(); + msg.setHeader(new Header(SERVER_GOODBYE_REQUEST, OPStatus.SUCCESS.getCode(), "graceful normal quit from access", + null)); + + //session.write2Client(msg); + ProxyTCPServer.scheduler.submit(new Runnable() { + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + } + }); + InetSocketAddress address = (InetSocketAddress) session.getContext().channel().remoteAddress(); + + closeSessionIfTimeout(session, mapping); + return address; + }catch (Exception e){ + logger.error("exception occur while serverGoodby2Client", e); + return null; + } + } + + public static InetSocketAddress goodBye2Client(Session session, + String errMsg, + int proxyStatus, + ClientSessionGroupMapping mapping) { + try { + long startTime = System.currentTimeMillis(); + Package msg = new Package(); + msg.setHeader(new Header(SERVER_GOODBYE_REQUEST, proxyStatus, errMsg,null)); + ProxyTCPServer.scheduler.schedule(new Runnable() { + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + } + }, 1 * 1000, TimeUnit.MILLISECONDS); + + closeSessionIfTimeout(session, mapping); + + return session.getRemoteAddress(); + } catch (Exception e) { + logger.error("exception occur while goodbye2client", e); + return null; + } + } + + public static void goodBye2Client(ChannelHandlerContext ctx, + String errMsg, + ClientSessionGroupMapping mapping, + ProxyTcpMonitor proxyTcpMonitor) { + long startTime = System.currentTimeMillis(); + Package pkg = new Package(new Header(SERVER_GOODBYE_REQUEST, OPStatus.FAIL.getCode(), + errMsg, null)); + proxyTcpMonitor.getProxy2clientMsgNum().incrementAndGet(); + logger.info("goodBye2Client client[{}]", RemotingHelper.parseChannelRemoteAddr(ctx.channel())); + ctx.writeAndFlush(pkg).addListener( + new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + Utils.logSucceedMessageFlow(pkg, null, startTime, startTime); + try { + mapping.closeSession(ctx); + } catch (Exception e) { + logger.warn("close session failed!", e); + } + } + } + ); + } + + public static String redirectClient2NewProxy(String newProxyIp, int port, Session session, ClientSessionGroupMapping mapping) { + logger.info("begin to gracefully redirect Client {}, newIPPort[{}]", session.getClient(), newProxyIp + ":" + port); + try { + long startTime = System.currentTimeMillis(); + + Package pkg = new Package(); + pkg.setHeader(new Header(REDIRECT_TO_CLIENT, OPStatus.SUCCESS.getCode(), null, + null)); + pkg.setBody(new RedirectInfo(newProxyIp, port)); + ProxyTCPServer.scheduler.schedule(new Runnable() { + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + Utils.writeAndFlush(pkg, startTime, taskExecuteTime, session.getContext(), session); + } + }, 5 * 1000, TimeUnit.MILLISECONDS); + closeSessionIfTimeout(session, mapping); + return session.getRemoteAddress() + "--->" + newProxyIp + ":" + port; + } catch (Exception e) { + logger.error("exception occur while redirectClient2NewProxy", e); + return null; + } + } + + public static void closeSessionIfTimeout(Session session, ClientSessionGroupMapping mapping) { + ProxyTCPServer.scheduler.schedule(new Runnable() { + @Override + public void run() { + try { + if(!session.getSessionState().equals(SessionState.CLOSED)){ + mapping.closeSession(session.getContext()); + logger.info("closeSessionIfTimeout success, session[{}]", session.getClient()); + } + } catch (Exception e) { + logger.error("close session failed", e); + } + } + }, 30 * 1000, TimeUnit.MILLISECONDS); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpConnectionHandler.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpConnectionHandler.java new file mode 100644 index 0000000000..6f3c510f19 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpConnectionHandler.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpConnectionHandler.java +package cn.webank.emesher.core.protocol.tcp.client; + +import cn.webank.emesher.boot.ProxyTCPServer; +======== +package com.webank.runtime.core.protocol.tcp.client; + +import com.webank.runtime.boot.ProxyTCPServer; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/ProxyTcpConnectionHandler.java +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.atomic.AtomicInteger; + +public class ProxyTcpConnectionHandler extends ChannelDuplexHandler { + + public static AtomicInteger connections = new AtomicInteger(0); + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private ProxyTCPServer proxyTCPServer; + + public ProxyTcpConnectionHandler(ProxyTCPServer proxyTCPServer) { + this.proxyTCPServer = proxyTCPServer; + } + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + logger.info("client|tcp|channelRegistered|remoteAddress={}|msg={}", remoteAddress, ""); + super.channelRegistered(ctx); + } + + @Override + public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + logger.info("client|tcp|channelUnregistered|remoteAddress={}|msg={}", remoteAddress, ""); + super.channelUnregistered(ctx); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + logger.info("client|tcp|channelActive|remoteAddress={}|msg={}", remoteAddress, ""); + + int c = connections.incrementAndGet(); + if (c > proxyTCPServer.getEventMeshConfiguration().proxyTcpClientMaxNum) { + logger.warn("client|tcp|channelActive|remoteAddress={}|msg={}", remoteAddress, "too many client connect " + + "this proxy server"); + ctx.close(); + return; + } + + super.channelActive(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + connections.decrementAndGet(); + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + logger.info("client|tcp|channelInactive|remoteAddress={}|msg={}", remoteAddress, ""); + proxyTCPServer.getClientSessionGroupMapping().closeSession(ctx); + super.channelInactive(ctx); + } + + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + if (event.state().equals(IdleState.ALL_IDLE)) { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + logger.info("client|tcp|userEventTriggered|remoteAddress={}|msg={}", remoteAddress, evt.getClass().getName()); + proxyTCPServer.getClientSessionGroupMapping().closeSession(ctx); + } + } + + ctx.fireUserEventTriggered(evt); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpExceptionHandler.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpExceptionHandler.java new file mode 100644 index 0000000000..a015eb088b --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpExceptionHandler.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpExceptionHandler.java +package cn.webank.emesher.core.protocol.tcp.client; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +======== +package com.webank.runtime.core.protocol.tcp.client; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/ProxyTcpExceptionHandler.java +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProxyTcpExceptionHandler extends ChannelDuplexHandler { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private ProxyTCPServer proxyTCPServer; + + public ProxyTcpExceptionHandler(ProxyTCPServer proxyTCPServer) { + this.proxyTCPServer = proxyTCPServer; + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + Session session = proxyTCPServer.getClientSessionGroupMapping().getSession(ctx); + UserAgent client = session == null ? null : session.getClient(); + logger.error("exceptionCaught, push goodbye to client|user={},errMsg={}", client, cause.fillInStackTrace()); + String errMsg; + if (cause.toString().contains("value not one of declared Enum instance names")) { + errMsg = "Unknown Command type"; + } else { + errMsg = cause.toString(); + } + + if (session != null) { + ProxyTcp2Client.goodBye2Client(session, errMsg, OPStatus.FAIL.getCode(), proxyTCPServer.getClientSessionGroupMapping()); + } else { + ProxyTcp2Client.goodBye2Client(ctx, errMsg, proxyTCPServer.getClientSessionGroupMapping(), proxyTCPServer.getProxyTcpMonitor()); + } + } + +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpMessageDispatcher.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpMessageDispatcher.java new file mode 100644 index 0000000000..363ecf267f --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpMessageDispatcher.java @@ -0,0 +1,161 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/ProxyTcpMessageDispatcher.java +package cn.webank.emesher.core.protocol.tcp.client; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.core.protocol.tcp.client.session.SessionState; +import cn.webank.emesher.core.protocol.tcp.client.task.GoodbyeTask; +import cn.webank.emesher.core.protocol.tcp.client.task.HeartBeatTask; +import cn.webank.emesher.core.protocol.tcp.client.task.HelloTask; +import cn.webank.emesher.core.protocol.tcp.client.task.ListenTask; +import cn.webank.emesher.core.protocol.tcp.client.task.MessageAckTask; +import cn.webank.emesher.core.protocol.tcp.client.task.MessageTransferTask; +import cn.webank.emesher.core.protocol.tcp.client.task.SubscribeTask; +import cn.webank.emesher.core.protocol.tcp.client.task.UnSubscribeTask; +import cn.webank.eventmesh.common.protocol.tcp.AccessMessage; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.core.protocol.tcp.client; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.core.protocol.tcp.client.session.SessionState; +import com.webank.runtime.core.protocol.tcp.client.task.GoodbyeTask; +import com.webank.runtime.core.protocol.tcp.client.task.HeartBeatTask; +import com.webank.runtime.core.protocol.tcp.client.task.HelloTask; +import com.webank.runtime.core.protocol.tcp.client.task.ListenTask; +import com.webank.runtime.core.protocol.tcp.client.task.MessageAckTask; +import com.webank.runtime.core.protocol.tcp.client.task.MessageTransferTask; +import com.webank.runtime.core.protocol.tcp.client.task.SubscribeTask; +import com.webank.runtime.core.protocol.tcp.client.task.UnSubscribeTask; +import com.webank.eventmesh.common.protocol.tcp.AccessMessage; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/ProxyTcpMessageDispatcher.java +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProxyTcpMessageDispatcher extends SimpleChannelInboundHandler { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final Logger messageLogger = LoggerFactory.getLogger("message"); + private ProxyTCPServer proxyTCPServer; + + public ProxyTcpMessageDispatcher(ProxyTCPServer proxyTCPServer) { + this.proxyTCPServer = proxyTCPServer; + } + @Override + protected void channelRead0(ChannelHandlerContext ctx, Package pkg) throws Exception { + long startTime = System.currentTimeMillis(); + validateMsg(pkg); + proxyTCPServer.getProxyTcpMonitor().getClient2proxyMsgNum().incrementAndGet(); + Command cmd = null; + try { + Runnable task; + cmd = pkg.getHeader().getCommand(); + if (cmd.equals(Command.HELLO_REQUEST)) { + messageLogger.info("pkg|c2proxy|cmd={}|pkg={}", cmd, pkg); + task = new HelloTask(pkg, ctx, startTime, proxyTCPServer); + ProxyTCPServer.taskHandleExecutorService.submit(task); + return; + } + + if (proxyTCPServer.getClientSessionGroupMapping().getSession(ctx) == null) { + messageLogger.info("pkg|c2proxy|cmd={}|pkg={},no session is found", cmd, pkg); + throw new Exception("no session is found"); + } + + logMessageFlow(ctx, pkg, cmd); + + if (proxyTCPServer.getClientSessionGroupMapping().getSession(ctx).getSessionState() == SessionState.CLOSED) { + throw new Exception("this proxy tcp session will be closed, may be reboot or version change!"); + } + + dispatch(ctx, pkg, startTime, cmd); + } catch (Exception e) { + logger.error("exception occurred while pkg|cmd={}|pkg={}|errMsg={}", cmd, pkg, e); + throw new RuntimeException(e); + } + } + + private void logMessageFlow(ChannelHandlerContext ctx, Package pkg, Command cmd) { + if (pkg.getBody() instanceof AccessMessage) { + messageLogger.info("pkg|c2proxy|cmd={}|Msg={}|user={}", cmd, ProxyUtil.printMqMessage((AccessMessage) pkg + .getBody()), proxyTCPServer.getClientSessionGroupMapping().getSession(ctx).getClient()); + } else { + messageLogger.info("pkg|c2proxy|cmd={}|pkg={}|user={}", cmd, pkg, proxyTCPServer.getClientSessionGroupMapping().getSession(ctx).getClient()); + } + } + + private void validateMsg(Package pkg) throws Exception { + if (pkg == null) { + throw new Exception("the incoming message is empty."); + } + if (pkg.getHeader() == null) { + logger.error("the incoming message does not have a header|pkg={}", pkg); + throw new Exception("the incoming message does not have a header."); + } + if (pkg.getHeader().getCommand() == null) { + logger.error("the incoming message does not have a command type|pkg={}", pkg); + throw new Exception("the incoming message does not have a command type."); + } + } + + private void dispatch(ChannelHandlerContext ctx, Package pkg, long startTime, Command cmd) throws + Exception { + Runnable task; + switch (cmd) { + case HEARTBEAT_REQUEST: + task = new HeartBeatTask(pkg, ctx, startTime, proxyTCPServer); + break; + case CLIENT_GOODBYE_REQUEST: + case SERVER_GOODBYE_RESPONSE: + task = new GoodbyeTask(pkg, ctx, startTime, proxyTCPServer); + break; + case SUBSCRIBE_REQUEST: + task = new SubscribeTask(pkg, ctx, startTime, proxyTCPServer); + break; + case UNSUBSCRIBE_REQUEST: + task = new UnSubscribeTask(pkg, ctx, startTime, proxyTCPServer); + break; + case LISTEN_REQUEST: + task = new ListenTask(pkg, ctx, startTime, proxyTCPServer); + break; + case REQUEST_TO_SERVER: + case RESPONSE_TO_SERVER: + case ASYNC_MESSAGE_TO_SERVER: + case BROADCAST_MESSAGE_TO_SERVER: + task = new MessageTransferTask(pkg, ctx, startTime, proxyTCPServer); + break; + case RESPONSE_TO_CLIENT_ACK: + case ASYNC_MESSAGE_TO_CLIENT_ACK: + case BROADCAST_MESSAGE_TO_CLIENT_ACK: + case REQUEST_TO_CLIENT_ACK: + task = new MessageAckTask(pkg, ctx, startTime, proxyTCPServer); + break; + default: + throw new Exception("unknown cmd"); + } + ProxyTCPServer.taskHandleExecutorService.submit(task); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/ClientGroupWrapper.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/ClientGroupWrapper.java new file mode 100644 index 0000000000..9de99784fc --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/ClientGroupWrapper.java @@ -0,0 +1,736 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/ClientGroupWrapper.java +package cn.webank.emesher.core.protocol.tcp.client.group; +======== +package com.webank.runtime.core.protocol.tcp.client.group; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/group/ClientGroupWrapper.java + +import cn.webank.defibus.client.common.DeFiBusClientConfig; +import cn.webank.defibus.client.impl.producer.RRCallback; +import cn.webank.defibus.consumer.DeFiBusPushConsumer; +import cn.webank.defibus.producer.DeFiBusProducer; +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.configuration.AccessConfiguration; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.group.dispatch.DownstreamDispatchStrategy; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.emesher.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import cn.webank.emesher.core.protocol.tcp.client.session.push.retry.ProxyTcpRetryer; +import cn.webank.emesher.core.protocol.tcp.client.session.send.UpStreamMsgContext; +import cn.webank.emesher.metrics.tcp.ProxyTcpMonitor; +import cn.webank.emesher.util.ProxyUtil; +import com.alibaba.fastjson.JSON; +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/ClientGroupWrapper.java +======== +import com.webank.defibus.client.common.DeFiBusClientConfig; +import com.webank.defibus.client.impl.producer.RRCallback; +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.configuration.AccessConfiguration; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.plugin.MQConsumerWrapper; +import com.webank.runtime.core.plugin.MQProducerWrapper; +import com.webank.runtime.core.protocol.tcp.client.group.dispatch.DownstreamDispatchStrategy; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.runtime.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import com.webank.runtime.core.protocol.tcp.client.session.push.retry.ProxyTcpRetryer; +import com.webank.runtime.core.protocol.tcp.client.session.send.UpStreamMsgContext; +import com.webank.runtime.metrics.tcp.ProxyTcpMonitor; +import com.webank.runtime.patch.ProxyConsumeConcurrentlyContext; +import com.webank.runtime.patch.ProxyConsumeConcurrentlyStatus; +import com.webank.runtime.patch.ProxyMessageListenerConcurrently; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/group/ClientGroupWrapper.java +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyContext; +import org.apache.rocketmq.client.impl.consumer.ProxyConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.impl.consumer.ProxyMessageListenerConcurrentlyOnce; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.common.utils.HttpTinyClient; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class ClientGroupWrapper { + + public static Logger logger = LoggerFactory.getLogger(ClientGroupWrapper.class); + + private String groupName; + + private String sysId; + + private String dcn; + + private AccessConfiguration accessConfiguration; + + private ProxyTCPServer proxyTCPServer; + + private ProxyTcpRetryer proxyTcpRetryer; + + private ProxyTcpMonitor proxyTcpMonitor; + + private DownstreamDispatchStrategy downstreamDispatchStrategy; + + private final ReadWriteLock groupLock = new ReentrantReadWriteLock(); + + public Set groupConsumerSessions = new HashSet(); + + public Set groupProducerSessions = new HashSet(); + + public AtomicBoolean started4Persistent = new AtomicBoolean(Boolean.FALSE); + + public AtomicBoolean started4Broadcast = new AtomicBoolean(Boolean.FALSE); + + public AtomicBoolean inited4Persistent = new AtomicBoolean(Boolean.FALSE); + + public AtomicBoolean inited4Broadcast = new AtomicBoolean(Boolean.FALSE); + + private DeFiBusClientConfig clientConfig4Clustering; + + private DeFiBusPushConsumer persistentMsgConsumer; + + private DeFiBusClientConfig clientConfig4Broadcasting; + + private DeFiBusPushConsumer broadCastMsgConsumer; + + private ConcurrentHashMap> topic2sessionInGroupMapping = new ConcurrentHashMap>(); + + private ConcurrentHashMap downstreamMap = new ConcurrentHashMap(); + + public ConcurrentHashMap getDownstreamMap() { + return downstreamMap; + } + + public AtomicBoolean producerStarted = new AtomicBoolean(Boolean.FALSE); + + public ConcurrentHashMap> getTopic2sessionInGroupMapping() { + return topic2sessionInGroupMapping; + } + + public boolean hasSubscription(String topic) { + boolean has = false; + try { + this.groupLock.readLock().lockInterruptibly(); + has = topic2sessionInGroupMapping.containsKey(topic); + } catch (Exception e) { + logger.error("hasSubscription error! topic[{}]", topic); + } finally { + this.groupLock.readLock().unlock(); + } + + return has; + } + + public boolean send(UpStreamMsgContext upStreamMsgContext, SendCallback sendCallback) throws Exception { + defibusProducer.publish(upStreamMsgContext.getMsg(), sendCallback); + return true; + } + + public void request(UpStreamMsgContext upStreamMsgContext, SendCallback sendCallback, RRCallback rrCallback, long timeout) + throws InterruptedException, RemotingException, MQClientException, MQBrokerException { + defibusProducer.request(upStreamMsgContext.getMsg(), sendCallback, rrCallback, timeout); + } + + public boolean reply(UpStreamMsgContext upStreamMsgContext) throws Exception { + defibusProducer.reply(upStreamMsgContext.getMsg(), new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + + } + + @Override + public void onException(Throwable e) { + String bizSeqNo = upStreamMsgContext.getMsg().getKeys(); + logger.error("reply err! topic:{}, bizSeqNo:{}, client:{}", upStreamMsgContext.getMsg().getTopic(), bizSeqNo, upStreamMsgContext.getSession().getClient(), e); + } + }); + return true; + } + + private DeFiBusProducer defibusProducer; + + public DeFiBusProducer getDefibusProducer() { + return defibusProducer; + } + + public boolean addSubscription(String topic, Session session) throws Exception { + if (session == null + || !StringUtils.equalsIgnoreCase(groupName, ProxyUtil.buildClientGroup(session.getClient().getSubsystem(), session.getClient().getDcn()))) { + logger.error("addSubscription param error,topic:{},session:{}",topic, session); + return false; + } + + boolean r = false; + try { + this.groupLock.writeLock().lockInterruptibly(); + if (!topic2sessionInGroupMapping.containsKey(topic)) { + Set sessions = new HashSet(); + topic2sessionInGroupMapping.put(topic, sessions); + } + r = topic2sessionInGroupMapping.get(topic).add(session); + if(r){ + logger.info("addSubscription success, group:{} topic:{} client:{}", groupName, topic, session.getClient()); + }else{ + logger.warn("addSubscription fail, group:{} topic:{} client:{}", groupName, topic, session.getClient()); + } + } catch (Exception e) { + logger.error("addSubscription error! topic:{} client:{}", topic, session.getClient(), e); + throw new Exception("addSubscription fail"); + } finally { + this.groupLock.writeLock().unlock(); + } + return r; + } + + public boolean removeSubscription(String topic, Session session) { + if (session == null + || !StringUtils.equalsIgnoreCase(groupName, ProxyUtil.buildClientGroup(session.getClient().getSubsystem(), session.getClient().getDcn()))) { + logger.error("removeSubscription param error,topic:{},session:{}",topic, session); + return false; + } + + boolean r = false; + try { + this.groupLock.writeLock().lockInterruptibly(); + if (topic2sessionInGroupMapping.containsKey(topic)) { + r = topic2sessionInGroupMapping.get(topic).remove(session); + if(r){ + logger.info("removeSubscription remove session success, group:{} topic:{} client:{}", groupName, topic, session.getClient()); + }else{ + logger.warn("removeSubscription remove session failed, group:{} topic:{} client:{}", groupName, topic, session.getClient()); + } + } + if (CollectionUtils.size(topic2sessionInGroupMapping.get(topic)) == 0) { + topic2sessionInGroupMapping.remove(topic); + logger.info("removeSubscription remove topic success, group:{} topic:{}", groupName, topic); + } + } catch (Exception e) { + logger.error("removeSubscription error! topic:{} client:{}", topic, session.getClient(), e); + } finally { + this.groupLock.writeLock().unlock(); + } + return r; + } + + public synchronized void startClientGroupProducer() throws MQClientException { + if (producerStarted.get()) { + return; + } + DeFiBusClientConfig wcc = new DeFiBusClientConfig(); + wcc.setClusterPrefix(accessConfiguration.proxyIDC); + wcc.setProducerGroup(ProxyUtil.buildClientProducerGroup(sysId, dcn)); + if (StringUtils.isEmpty(accessConfiguration.namesrvAddr)) { + wcc.setWsAddr(ProxyUtil.buildCCAddr(accessConfiguration.configCenterAddr)); + } else { + wcc.setNamesrvAddr(accessConfiguration.namesrvAddr); + } + + MessageClientIDSetter.createUniqID(); + defibusProducer = new DeFiBusProducer(wcc); + defibusProducer.getDefaultMQProducer().setVipChannelEnabled(false); + defibusProducer.getDefaultMQProducer().setInstanceName(ProxyUtil.buildProxyTcpClientID(sysId, dcn, "PUB", accessConfiguration.proxyCluster));//设置实例名称 + defibusProducer.getDefaultMQProducer().setCompressMsgBodyOverHowmuch(1024 * 2); + + defibusProducer.start(); + producerStarted.compareAndSet(false, true); + logger.info("starting producer success, group:{} clientConfig:{}", groupName, wcc); + } + + public synchronized void shutdownProducer() { + if (!producerStarted.get()) { + return; + } + defibusProducer.shutdown(); + producerStarted.compareAndSet(true, false); + logger.info("shutdown producer success for group:{}", groupName); + } + + public ClientGroupWrapper(String sysId, String dcn, + ProxyTCPServer proxyTCPServer, + DownstreamDispatchStrategy downstreamDispatchStrategy) { + this.sysId = sysId; + this.dcn = dcn; + this.proxyTCPServer = proxyTCPServer; + this.accessConfiguration = proxyTCPServer.getAccessConfiguration(); + this.proxyTcpRetryer = proxyTCPServer.getProxyTcpRetryer(); + this.proxyTcpMonitor = proxyTCPServer.getProxyTcpMonitor(); + this.groupName = ProxyUtil.buildClientGroup(sysId, dcn); + this.downstreamDispatchStrategy = downstreamDispatchStrategy; + } + + public String getGroupName() { + return groupName; + } + + public boolean addGroupConsumerSession(Session session) { + if (session == null + || !StringUtils.equalsIgnoreCase(groupName, ProxyUtil.buildClientGroup(session.getClient().getSubsystem(), session.getClient().getDcn()))) { + logger.error("addGroupConsumerSession param error,session:{}", session); + return false; + } + + boolean r = false; + try { + this.groupLock.writeLock().lockInterruptibly(); + r = groupConsumerSessions.add(session); + if (r) { + logger.info("addGroupConsumerSession success, group:{} client:{}", groupName, session.getClient()); + } + } catch (Exception e) { + logger.error("addGroupConsumerSession error! group:{} client:{}", groupName, session.getClient(), e); + } finally { + this.groupLock.writeLock().unlock(); + } + return r; + } + + public boolean addGroupProducerSession(Session session) { + if (session == null + || !StringUtils.equalsIgnoreCase(groupName, ProxyUtil.buildClientGroup(session.getClient().getSubsystem(), session.getClient().getDcn()))) { + logger.error("addGroupProducerSession param error,session:{}", session); + return false; + } + + boolean r = false; + try { + this.groupLock.writeLock().lockInterruptibly(); + r = groupProducerSessions.add(session); + if (r) { + logger.info("addGroupProducerSession success, group:{} client:{}", groupName, session.getClient()); + } + } catch (Exception e) { + logger.error("addGroupProducerSession error! group:{} client:{}", groupName, session.getClient(), e); + } finally { + this.groupLock.writeLock().unlock(); + } + return r; + } + + public boolean removeGroupConsumerSession(Session session) { + if (session == null + || !StringUtils.equalsIgnoreCase(groupName, ProxyUtil.buildClientGroup(session.getClient().getSubsystem(), session.getClient().getDcn()))) { + logger.error("removeGroupConsumerSession param error,session:{}", session); + return false; + } + + boolean r = false; + try { + this.groupLock.writeLock().lockInterruptibly(); + r = groupConsumerSessions.remove(session); + if (r) { + logger.info("removeGroupConsumerSession success, group:{} client:{}", groupName, session.getClient()); + } + } catch (Exception e) { + logger.error("removeGroupConsumerSession error! group:{} client:{}", groupName, session.getClient(), e); + } finally { + this.groupLock.writeLock().unlock(); + } + return r; + } + + public boolean removeGroupProducerSession(Session session) { + if (session == null + || !StringUtils.equalsIgnoreCase(groupName, ProxyUtil.buildClientGroup(session.getClient().getSubsystem(), session.getClient().getDcn()))) { + logger.error("removeGroupProducerSession param error,session:{}", session); + return false; + } + + boolean r = false; + try { + this.groupLock.writeLock().lockInterruptibly(); + r = groupProducerSessions.remove(session); + if (r) { + logger.info("removeGroupProducerSession success, group:{} client:{}", groupName, session.getClient()); + } + } catch (Exception e) { + logger.error("removeGroupProducerSession error! group:{} client:{}", groupName, session.getClient(), e); + } finally { + this.groupLock.writeLock().unlock(); + } + + return r; + } + + private DeFiBusClientConfig initDefibusClientConfig(boolean broadcast) { + DeFiBusClientConfig wcc = new DeFiBusClientConfig(); + wcc.setPubWindowSize(accessConfiguration.pubWindow); + wcc.setAckWindowSize(accessConfiguration.ackWindow); + wcc.setThreadPoolCoreSize(accessConfiguration.consumeThreadMin); + wcc.setThreadPoolMaxSize(accessConfiguration.consumeThreadMax); + wcc.setPullBatchSize(accessConfiguration.pullBatchSize); + wcc.setClusterPrefix(accessConfiguration.proxyIDC); + + wcc.setConsumeTimeout(accessConfiguration.consumeTimeout); + if (broadcast) { + wcc.setConsumerGroup(ProxyUtil.buildBroadcastClientConsumerGroup(sysId, dcn)); + } else { + wcc.setConsumerGroup(ProxyUtil.buildPersistentClientConsumerGroup(sysId, dcn)); + } + + if (StringUtils.isEmpty(accessConfiguration.namesrvAddr)) { + wcc.setWsAddr(ProxyUtil.buildCCAddr(accessConfiguration.configCenterAddr)); + } else { + wcc.setNamesrvAddr(accessConfiguration.namesrvAddr); + } + + return wcc; + } + + public synchronized void initClientGroupPersistentConsumer() { + if(inited4Persistent.get()){ + return; + } + clientConfig4Clustering = initDefibusClientConfig(false); + persistentMsgConsumer = new DeFiBusPushConsumer(clientConfig4Clustering); + persistentMsgConsumer.getDefaultMQPushConsumer().setInstanceName(ProxyUtil.buildProxyTcpClientID(sysId, dcn, "SUB", accessConfiguration.proxyCluster)); + persistentMsgConsumer.getDefaultMQPushConsumer().setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); + persistentMsgConsumer.getDefaultMQPushConsumer().setMessageModel(MessageModel.CLUSTERING); + persistentMsgConsumer.getDefaultMQPushConsumer().setNamesrvAddr(clientConfig4Clustering.getNamesrvAddr()); + persistentMsgConsumer.registerMessageListener(new ProxyMessageListenerConcurrentlyOnce() { + + @Override + public ProxyConsumeConcurrentlyStatus handleMessage(MessageExt msg, ConsumeMessageConcurrentlyContext context) { + + if (msg == null) + return ProxyConsumeConcurrentlyStatus.CONSUME_SUCCESS; + + proxyTcpMonitor.getMq2proxyMsgNum().incrementAndGet(); + String topic = msg.getTopic(); + msg.putUserProperty(ProxyConstants.REQ_MQ2PROXY_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + msg.putUserProperty(ProxyConstants.REQ_RECEIVE_PROXY_IP, ProxyUtil.getLocalAddr()); + msg.putUserProperty(ProxyConstants.BORN_TIMESTAMP, String.valueOf(msg.getBornTimestamp())); + msg.putUserProperty(ProxyConstants.STORE_TIMESTAMP, String.valueOf(msg.getStoreTimestamp())); + + if (!ProxyUtil.isValidRMBTopic(topic)) { + return ProxyConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + + Session session = downstreamDispatchStrategy.select(groupName, topic, groupConsumerSessions); + String bizSeqNo = ProxyUtil.getMessageBizSeq(msg); + if(session == null){ + try { + Integer sendBackTimes = MapUtils.getInteger(msg.getProperties(), ProxyConstants.PROXY_SEND_BACK_TIMES, new Integer(0)); + String sendBackFromProxyIp = MapUtils.getString(msg.getProperties(), ProxyConstants.PROXY_SEND_BACK_IP, ""); + logger.error("found no session to downstream msg,groupName:{}, topic:{}, bizSeqNo:{}", groupName, topic, bizSeqNo); + + if (sendBackTimes >= proxyTCPServer.getAccessConfiguration().proxyTcpSendBackMaxTimes) { + logger.error("sendBack to broker over max times:{}, groupName:{}, topic:{}, bizSeqNo:{}", proxyTCPServer.getAccessConfiguration().proxyTcpSendBackMaxTimes, groupName, topic, bizSeqNo); + } else { + sendBackTimes++; + msg.putUserProperty(ProxyConstants.PROXY_SEND_BACK_TIMES, sendBackTimes.toString()); + msg.putUserProperty(ProxyConstants.PROXY_SEND_BACK_IP, sendBackFromProxyIp); + sendMsgBackToBroker(msg, bizSeqNo); + } + } catch (Exception e){ + logger.warn("handle msg exception when no session found", e); + } + + return ProxyConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + + DownStreamMsgContext downStreamMsgContext = + new DownStreamMsgContext(msg, session, persistentMsgConsumer, (ConsumeMessageConcurrentlyContext)context, false); + + if(downstreamMap.size() < proxyTCPServer.getAccessConfiguration().proxyTcpDownStreamMapSize){ + downstreamMap.putIfAbsent(downStreamMsgContext.seq, downStreamMsgContext); + }else{ + logger.warn("downStreamMap is full,group:{}", groupName); + } + + if (session.isCanDownStream()) { + session.downstreamMsg(downStreamMsgContext); + return ProxyConsumeConcurrentlyStatus.CONSUME_FINISH; + } + + logger.warn("session is busy,dispatch retry,seq:{}, session:{}, bizSeq:{}", downStreamMsgContext.seq, downStreamMsgContext.session.getClient(), bizSeqNo); + long delayTime = ProxyUtil.isService(downStreamMsgContext.msgExt.getTopic()) ? 0 : proxyTCPServer.getAccessConfiguration().proxyTcpMsgRetryDelayInMills; + downStreamMsgContext.delay(delayTime); + proxyTcpRetryer.pushRetry(downStreamMsgContext); + + return ProxyConsumeConcurrentlyStatus.CONSUME_FINISH; + } + }); + inited4Persistent.compareAndSet(false, true); + logger.info("init persistentMsgConsumer success, group:{} persistentMsgConsumerMQClientConfig:{}", groupName, clientConfig4Clustering); + } + + public synchronized void startClientGroupPersistentConsumer() throws MQClientException { + if (started4Persistent.get()) { + return; + } + persistentMsgConsumer.start(); + persistentMsgConsumer.getDefaultMQPushConsumer().unsubscribe(MixAll.getRetryTopic(clientConfig4Clustering.getConsumerGroup())); + started4Persistent.compareAndSet(false, true); + logger.info("starting persistentMsgConsumer success, group:{}", groupName); + } + + public synchronized void initClientGroupBroadcastConsumer() { + if(inited4Broadcast.get()){ + return; + } + clientConfig4Broadcasting = initDefibusClientConfig(true); + broadCastMsgConsumer = new DeFiBusPushConsumer(clientConfig4Broadcasting); + broadCastMsgConsumer.getDefaultMQPushConsumer().setInstanceName(ProxyUtil.buildProxyTcpClientID(sysId, dcn, "SUB", accessConfiguration.proxyCluster)); + broadCastMsgConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); + broadCastMsgConsumer.getDefaultMQPushConsumer().setMessageModel(MessageModel.BROADCASTING); + broadCastMsgConsumer.setNamesrvAddr(clientConfig4Broadcasting.getNamesrvAddr()); + broadCastMsgConsumer.registerMessageListener(new ProxyMessageListenerConcurrentlyOnce() { + @Override + public ProxyConsumeConcurrentlyStatus handleMessage(MessageExt msg, ConsumeMessageConcurrentlyContext context) { + if (msg == null) + return ProxyConsumeConcurrentlyStatus.CONSUME_SUCCESS; + + proxyTcpMonitor.getMq2proxyMsgNum().incrementAndGet(); + + String topic = msg.getTopic(); + + msg.putUserProperty(ProxyConstants.REQ_MQ2PROXY_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + msg.putUserProperty(ProxyConstants.REQ_RECEIVE_PROXY_IP, ProxyUtil.getLocalAddr()); + msg.putUserProperty(ProxyConstants.BORN_TIMESTAMP, String.valueOf(msg.getBornTimestamp())); + msg.putUserProperty(ProxyConstants.STORE_TIMESTAMP, String.valueOf(msg.getStoreTimestamp())); + + if (!ProxyUtil.isValidRMBTopic(topic)) { + return ProxyConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + + if(CollectionUtils.isEmpty(groupConsumerSessions)){ + logger.warn("found no session to downstream broadcast msg"); + return ProxyConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + + Iterator sessionsItr = groupConsumerSessions.iterator(); + + while (sessionsItr.hasNext()) { + Session session = sessionsItr.next(); + + if (!session.isAvailable(topic)) { + logger.warn("downstream broadcast msg,session is not available,client:{}",session.getClient()); + continue; + } + + DownStreamMsgContext downStreamMsgContext = + new DownStreamMsgContext(msg, session, broadCastMsgConsumer, context, false); + + if (session.isCanDownStream()) { + session.downstreamMsg(downStreamMsgContext); + continue; + } + + logger.warn("downstream broadcast msg,session is busy,dispatch retry,seq:{}, session:{}, bizSeq:{}", downStreamMsgContext.seq, downStreamMsgContext.session.getClient(), ProxyUtil.getMessageBizSeq(downStreamMsgContext.msgExt)); + long delayTime = ProxyUtil.isService(downStreamMsgContext.msgExt.getTopic()) ? 0 : proxyTCPServer.getAccessConfiguration().proxyTcpMsgRetryDelayInMills; + downStreamMsgContext.delay(delayTime); + proxyTcpRetryer.pushRetry(downStreamMsgContext); + } + + return ProxyConsumeConcurrentlyStatus.CONSUME_FINISH; + } + }); + inited4Broadcast.compareAndSet(false, true); + logger.info("init broadCastMsgConsumer success, group:{} broadcastMsgConsumerMQClientConfig:{}", groupName, clientConfig4Broadcasting); + } + + public synchronized void startClientGroupBroadcastConsumer() throws MQClientException{ + if (started4Broadcast.get()) { + return; + } + broadCastMsgConsumer.start(); + broadCastMsgConsumer.getDefaultMQPushConsumer().unsubscribe(MixAll.getRetryTopic(clientConfig4Broadcasting.getConsumerGroup())); + started4Broadcast.compareAndSet(false, true); + logger.info("starting broadCastMsgConsumer success, group:{}", groupName); + } + + public void subscribe(String topic) throws Exception { + if (ProxyUtil.isBroadcast(topic)) { + broadCastMsgConsumer.subscribe(topic); + } else { + persistentMsgConsumer.subscribe(topic); + } + } + + public void unsubscribe(String topic) { + if (ProxyUtil.isBroadcast(topic)) { + broadCastMsgConsumer.unsubscribe(topic); + } else { + persistentMsgConsumer.unsubscribe(topic); + } + } + + public synchronized void shutdownBroadCastConsumer() { + if (started4Broadcast.get()) { + broadCastMsgConsumer.shutdown(); + logger.info("broadcast consumer group:{} shutdown...", groupName); + } + started4Broadcast.compareAndSet(true, false); + inited4Broadcast.compareAndSet(true, false); + broadCastMsgConsumer = null; + clientConfig4Broadcasting = null; + } + + public synchronized void shutdownPersistentConsumer() { + + if (started4Persistent.get()) { + persistentMsgConsumer.shutdown(); + logger.info("persistent consumer group:{} shutdown...", groupName); + } + started4Persistent.compareAndSet(true, false); + inited4Persistent.compareAndSet(true,false); + persistentMsgConsumer = null; + clientConfig4Clustering = null; + } + + public Set getGroupConsumerSessions() { + Set res = null; + try { + this.groupLock.readLock().lockInterruptibly(); + res = groupConsumerSessions; + } catch (Exception e) { + } finally { + this.groupLock.readLock().unlock(); + } + return res; + } + + + public Set getGroupProducerSessions() { + Set res = null; + try { + this.groupLock.readLock().lockInterruptibly(); + res = groupProducerSessions; + } catch (Exception e) { + } finally { + this.groupLock.readLock().unlock(); + } + return res; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public AccessConfiguration getAccessConfiguration() { + return accessConfiguration; + } + + public void setAccessConfiguration(AccessConfiguration accessConfiguration) { + this.accessConfiguration = accessConfiguration; + } + + public ProxyTcpRetryer getProxyTcpRetryer() { + return proxyTcpRetryer; + } + + public void setProxyTcpRetryer(ProxyTcpRetryer proxyTcpRetryer) { + this.proxyTcpRetryer = proxyTcpRetryer; + } + + public ProxyTcpMonitor getProxyTcpMonitor() { + return proxyTcpMonitor; + } + + public void setProxyTcpMonitor(ProxyTcpMonitor proxyTcpMonitor) { + this.proxyTcpMonitor = proxyTcpMonitor; + } + + public DownstreamDispatchStrategy getDownstreamDispatchStrategy() { + return downstreamDispatchStrategy; + } + + public void setDownstreamDispatchStrategy(DownstreamDispatchStrategy downstreamDispatchStrategy) { + this.downstreamDispatchStrategy = downstreamDispatchStrategy; + } + + public String getSysId() { + return sysId; + } + + private String pushMsgToProxy(MessageExt msg, String ip, int port) { + StringBuilder targetUrl = new StringBuilder(); + targetUrl.append("http://").append(ip).append(":").append(port).append("/proxy/msg/push"); + HttpTinyClient.HttpResult result = null; + + try { + logger.info("pushMsgToProxy,targetUrl:{},msg:{}",targetUrl.toString(),msg.toString()); + List paramValues = new ArrayList(); + paramValues.add("msg"); + paramValues.add(JSON.toJSONString(msg)); + paramValues.add("group"); + paramValues.add(groupName); + + result = HttpTinyClient.httpPost( + targetUrl.toString(), + null, + paramValues, + "UTF-8", + 3000); + } catch (Exception e) { + throw new RuntimeException("httpPost " + targetUrl + " is fail," + e); + } + + if (200 == result.code && result.content != null) { + return result.content; + + } else { + throw new RuntimeException("httpPost targetUrl[" + targetUrl + "] is not OK when getContentThroughHttp, httpResult: " + result + "."); + } + } + + public DeFiBusPushConsumer getPersistentMsgConsumer() { + return persistentMsgConsumer; + } + + private void sendMsgBackToBroker(MessageExt msg, String bizSeqNo){ + try { + logger.warn("send msg back to broker, bizSeqno:{}, topic:{}",bizSeqNo, msg.getTopic()); + + send(new UpStreamMsgContext(null,null, msg), new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + logger.info("consumerGroup:{} consume fail, sendMessageBack success, bizSeqno:{}, topic:{}", groupName, bizSeqNo, msg.getTopic()); + } + + @Override + public void onException(Throwable e) { + logger.warn("consumerGroup:{} consume fail, sendMessageBack fail, bizSeqno:{}, topic:{}", groupName, bizSeqNo, msg.getTopic()); + } + }); + proxyTcpMonitor.getProxy2mqMsgNum().incrementAndGet(); + }catch (Exception e){ + logger.warn("try send msg back to broker failed"); + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/ClientSessionGroupMapping.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/ClientSessionGroupMapping.java new file mode 100644 index 0000000000..a59fa7fca1 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/ClientSessionGroupMapping.java @@ -0,0 +1,506 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/ClientSessionGroupMapping.java +package cn.webank.emesher.core.protocol.tcp.client.group; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.ProxyTcp2Client; +import cn.webank.emesher.core.protocol.tcp.client.group.dispatch.FreePriorityDispatchStrategy; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.emesher.core.protocol.tcp.client.session.SessionState; +import cn.webank.emesher.core.protocol.tcp.client.session.push.ClientAckContext; +import cn.webank.emesher.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import cn.webank.eventmesh.common.ThreadUtil; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.core.protocol.tcp.client.group; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.tcp.client.ProxyTcp2Client; +import com.webank.runtime.core.protocol.tcp.client.group.dispatch.FreePriorityDispatchStrategy; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.runtime.core.protocol.tcp.client.session.SessionState; +import com.webank.runtime.core.protocol.tcp.client.session.push.ClientAckContext; +import com.webank.runtime.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import com.webank.runtime.util.ProxyUtil; +import com.webank.eventmesh.common.ThreadUtil; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/group/ClientSessionGroupMapping.java +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.ref.WeakReference; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class ClientSessionGroupMapping { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final Logger sessionLogger = LoggerFactory.getLogger("sessionLogger"); + + private ConcurrentHashMap sessionTable = new ConcurrentHashMap<>(); + + private ConcurrentHashMap clientGroupMap = new ConcurrentHashMap(); + + private ConcurrentHashMap lockMap = new ConcurrentHashMap(); + + private ProxyTCPServer proxyTCPServer; + + public ClientSessionGroupMapping(ProxyTCPServer proxyTCPServer) { + this.proxyTCPServer = proxyTCPServer; + } + + public ProxyTCPServer getProxyTCPServer() { + return proxyTCPServer; + } + + public void setProxyTCPServer(ProxyTCPServer proxyTCPServer) { + this.proxyTCPServer = proxyTCPServer; + } + + public ClientGroupWrapper getClientGroupWrapper(String groupName) { + return MapUtils.getObject(clientGroupMap, groupName, null); + } + + public Session getSession(ChannelHandlerContext ctx) { + Session session = getSession((InetSocketAddress) ctx.channel().remoteAddress()); + return session; + } + + public Session getSession(InetSocketAddress address) { + return sessionTable.get(address); + } + + public Session createSession(UserAgent user, ChannelHandlerContext ctx) throws Exception { + InetSocketAddress addr = (InetSocketAddress) ctx.channel().remoteAddress(); + user.setHost(addr.getHostString()); + user.setPort(addr.getPort()); + Session session = null; + if(!sessionTable.containsKey(addr)){ + logger.info("createSession client[{}]", RemotingHelper.parseChannelRemoteAddr(ctx.channel())); + session = new Session(user, ctx, proxyTCPServer.getEventMeshConfiguration()); + initClientGroupWrapper(user, session); + sessionTable.put(addr, session); + sessionLogger.info("session|open|succeed|user={}", user); + }else { + session = sessionTable.get(addr); + sessionLogger.error("session|open|failed|user={}|msg={}", user, "session has been created!"); + } + return session; + } + + public void readySession(Session session) throws Exception { + if (!ProxyConstants.PURPOSE_SUB.equals(session.getClient().getPurpose())) { + throw new Exception("client purpose config is not sub"); + } + startClientGroupConsumer(session); + } + + public synchronized void closeSession(ChannelHandlerContext ctx) throws Exception { + + InetSocketAddress addr = (InetSocketAddress) ctx.channel().remoteAddress(); + Session session = MapUtils.getObject(sessionTable, addr, null); + if (session == null) { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + logger.info("begin to close channel to remote address[{}]", remoteAddress); + ctx.channel().close().addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + logger.info("close the connection to remote address[{}] result: {}", remoteAddress, + future.isSuccess()); + } + }); + sessionLogger.info("session|close|succeed|address={}|msg={}", addr, "no session was found"); + return; + } + + closeSession(session); + + //remove session from sessionTable + sessionTable.remove(addr); + + sessionLogger.info("session|close|succeed|user={}", session.getClient()); + } + + private void closeSession(Session session){ + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(session.getContext().channel()); + if (SessionState.CLOSED == session.getSessionState()) { + logger.info("session has been closed, addr:{}", remoteAddress); + return; + } + + //session must be synchronized to avoid SessionState be confound, for example adding subscribe when session closing + synchronized (session){ + + if (SessionState.CLOSED == session.getSessionState()) { + logger.info("session has been closed in sync, addr:{}", remoteAddress); + return; + } + + session.setSessionState(SessionState.CLOSED); + + if (ProxyConstants.PURPOSE_SUB.equals(session.getClient().getPurpose())) { + cleanClientGroupWrapperByCloseSub(session); + }else if (ProxyConstants.PURPOSE_PUB.equals(session.getClient().getPurpose())) { + cleanClientGroupWrapperByClosePub(session); + }else{ + logger.error("client purpose config is error:{}", session.getClient().getPurpose()); + } + + if (session.getContext() != null) { + logger.info("begin to close channel to remote address[{}]", remoteAddress); + session.getContext().channel().close().addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + logger.info("close the connection to remote address[{}] result: {}", remoteAddress, + future.isSuccess()); + } + }); + } + } + } + + private void initClientGroupWrapper(UserAgent user, Session session) throws Exception { + final String clientGroup = ProxyUtil.buildClientGroup(user.getSubsystem(), user.getDcn()); + if(!lockMap.containsKey(clientGroup)){ + Object obj = lockMap.putIfAbsent(clientGroup, new Object()); + if(obj == null) { + logger.info("add lock to map for group:{}", clientGroup); + } + } + synchronized (lockMap.get(clientGroup)) { + if (!clientGroupMap.containsKey(clientGroup)) { + ClientGroupWrapper cgw = new ClientGroupWrapper(user.getSubsystem(), user.getDcn() + , proxyTCPServer, new FreePriorityDispatchStrategy()); + clientGroupMap.put(clientGroup, cgw); + logger.info("create new ClientGroupWrapper,group:{}", clientGroup); + } + + ClientGroupWrapper cgw = clientGroupMap.get(clientGroup); + + if (ProxyConstants.PURPOSE_PUB.equals(user.getPurpose())){ + startClientGroupProducer(cgw, session); + }else if (ProxyConstants.PURPOSE_SUB.equals(user.getPurpose())) { + initClientGroupConsumser(cgw); + }else{ + logger.error("unknown client purpose:{}", user.getPurpose()); + throw new Exception("client purpose config is error"); + } + + session.setClientGroupWrapper(new WeakReference(cgw)); + } + } + + private void startClientGroupProducer(ClientGroupWrapper cgw, Session session) throws Exception { + if (!cgw.producerStarted.get()) { + cgw.startClientGroupProducer(); + } + boolean flag = cgw.addGroupProducerSession(session); + if(!flag){ + throw new Exception("addGroupProducerSession fail"); + } + session.setSessionState(SessionState.RUNNING); + } + + private void initClientGroupConsumser(ClientGroupWrapper cgw) throws MQClientException { + if (!cgw.producerStarted.get()) { + cgw.startClientGroupProducer(); + } + + if (!cgw.inited4Broadcast.get()) { + cgw.initClientGroupBroadcastConsumer(); + } + + if (!cgw.inited4Persistent.get()) { + cgw.initClientGroupPersistentConsumer(); + } + } + + private void startClientGroupConsumer(Session session) throws Exception { + final String clientGroup = ProxyUtil.buildClientGroup(session.getClient().getSubsystem(), session.getClient().getDcn()); + if(!lockMap.containsKey(clientGroup)){ + lockMap.putIfAbsent(clientGroup, new Object()); + } + synchronized (lockMap.get(clientGroup)) { + logger.info("readySession session[{}]", session); + ClientGroupWrapper cgw = session.getClientGroupWrapper().get(); + + boolean flag = cgw.addGroupConsumerSession(session); + if(!flag){ + throw new Exception("addGroupConsumerSession fail"); + } + + if (cgw.inited4Persistent.get() && !cgw.started4Persistent.get()) { + cgw.startClientGroupPersistentConsumer(); + } + if (cgw.inited4Broadcast.get() && !cgw.started4Broadcast.get()) { + cgw.startClientGroupBroadcastConsumer(); + } + session.setSessionState(SessionState.RUNNING); + } + } + + private void cleanClientGroupWrapperByCloseSub(Session session){ + cleanSubscriptionInSession(session); + session.getClientGroupWrapper().get().removeGroupConsumerSession(session); + handleUnackMsgsInSession(session); + cleanClientGroupWrapperCommon(session); + } + + private void cleanClientGroupWrapperByClosePub(Session session){ + session.getClientGroupWrapper().get().removeGroupProducerSession(session); + cleanClientGroupWrapperCommon(session); + } + + /** + * clean subscription of the session + * + * @param session + */ + private void cleanSubscriptionInSession(Session session){ + for (String topic : session.getSessionContext().subscribeTopics.values()) { + session.getClientGroupWrapper().get().removeSubscription(topic, session); + if (!session.getClientGroupWrapper().get().hasSubscription(topic)) { + session.getClientGroupWrapper().get().unsubscribe(topic); + } + } + } + + /** + * handle unAck msgs in this session + * + * @param session + */ + private void handleUnackMsgsInSession(Session session){ + ConcurrentHashMap unAckMsg = session.getPusher().getPushContext().getUnAckMsg(); + if(unAckMsg.size() > 0 && session.getClientGroupWrapper().get().getGroupConsumerSessions().size() > 0){ + for(Map.Entry entry : unAckMsg.entrySet()){ + ClientAckContext ackContext = entry.getValue(); + if(ProxyUtil.isBroadcast(ackContext.getMsgs().get(0).getTopic())){ + logger.warn("exist broadcast msg unack when closeSession,seq:{},bizSeq:{},client:{}",ackContext.getSeq(),ProxyUtil.getMessageBizSeq(ackContext.getMsgs().get(0)),session.getClient()); + continue; + } + List list = new ArrayList(session.getClientGroupWrapper().get().getGroupConsumerSessions()); + Collections.shuffle(list); + DownStreamMsgContext downStreamMsgContext= new DownStreamMsgContext(ackContext.getMsgs().get(0),list.get(0),ackContext.getConsumer(), ackContext.getContext(), false); + + downStreamMsgContext.delay(0L); + proxyTCPServer.getProxyTcpRetryer().pushRetry(downStreamMsgContext); + logger.warn("rePush msg form unAckMsgs,seq:{},rePushSeq:{},rePushClient:{}",entry.getKey(), downStreamMsgContext.seq, downStreamMsgContext.session.getClient()); + } + } + } + + private void cleanClientGroupWrapperCommon(Session session){ + logger.info("GroupConsumerSessions size:{}", session.getClientGroupWrapper().get().getGroupConsumerSessions().size()); + if (session.getClientGroupWrapper().get().getGroupConsumerSessions().size() == 0) { + shutdownClientGroupConsumer(session); + } + + logger.info("GroupProducerSessions size:{}", session.getClientGroupWrapper().get().getGroupProducerSessions().size()); + if ((session.getClientGroupWrapper().get().getGroupConsumerSessions().size() == 0) + && (session.getClientGroupWrapper().get().getGroupProducerSessions().size() == 0)) { + shutdownClientGroupProducer(session); + + clientGroupMap.remove(session.getClientGroupWrapper().get().getGroupName()); + lockMap.remove(session.getClientGroupWrapper().get().getGroupName()); + logger.info("remove clientGroupWrapper group[{}]", session.getClientGroupWrapper().get().getGroupName()); + } + } + + private void shutdownClientGroupConsumer(Session session){ + if (session.getClientGroupWrapper().get().started4Broadcast.get() == Boolean.TRUE) { + session.getClientGroupWrapper().get().shutdownBroadCastConsumer(); + } + + if (session.getClientGroupWrapper().get().started4Persistent.get() == Boolean.TRUE) { + session.getClientGroupWrapper().get().shutdownPersistentConsumer(); + } + } + + + private void shutdownClientGroupProducer(Session session){ + if (session.getClientGroupWrapper().get().producerStarted.get() == Boolean.TRUE) { + session.getClientGroupWrapper().get().shutdownProducer(); + } + } + + private void initSessionCleaner() { + ProxyTCPServer.scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + Iterator sessionIterator = sessionTable.values().iterator(); + while (sessionIterator.hasNext()) { + Session tmp = sessionIterator.next(); + if (System.currentTimeMillis() - tmp.getLastHeartbeatTime() > proxyTCPServer.getEventMeshConfiguration().proxyTcpSessionExpiredInMills) { + try { + logger.warn("clean expired session,client:{}", tmp.getClient()); + closeSession(tmp.getContext()); + } catch (Exception e) { + logger.error("say goodbye to session error! {}", tmp, e); + } + } + } + } + }, 1000, proxyTCPServer.getEventMeshConfiguration().proxyTcpSessionExpiredInMills, TimeUnit.MILLISECONDS); + } + + private void initSessionAckContextCleaner() { + proxyTCPServer.scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + Iterator sessionIterator = sessionTable.values().iterator(); + while (sessionIterator.hasNext()) { + Session tmp = sessionIterator.next(); + for (Map.Entry entry : tmp.getPusher().getPushContext().getUnAckMsg().entrySet()) { + String seqKey = entry.getKey(); + ClientAckContext clientAckContext = entry.getValue(); + if (!clientAckContext.isExpire()) { + continue; + } + tmp.getPusher().getPushContext().ackMsg(seqKey); + tmp.getPusher().getPushContext().getUnAckMsg().remove(seqKey); + logger.warn("remove expire clientAckContext, session:{}, topic:{}, seq:{}", tmp, clientAckContext.getMsgs().get(0).getTopic(), seqKey); + } + } + } + }, 1000, 5 * 1000, TimeUnit.MILLISECONDS); + } + + private void initDownStreamMsgContextCleaner() { + proxyTCPServer.scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + Iterator cgwIterator = clientGroupMap.values().iterator(); + while (cgwIterator.hasNext()) { + ClientGroupWrapper cgw = cgwIterator.next(); + for (Map.Entry entry : cgw.getDownstreamMap().entrySet()) { + String seq = entry.getKey(); + DownStreamMsgContext downStreamMsgContext = entry.getValue(); + if (!downStreamMsgContext.isExpire()) { + continue; + } + cgw.getDownstreamMap().get(seq).ackMsg(); + cgw.getDownstreamMap().remove(seq); + logger.warn("remove expire DownStreamMsgContext,group:{}, topic:{}, seq:{}", cgw.getGroupName(), downStreamMsgContext.msgExt.getTopic(), seq); + } + } + } + }, 1000, 5 * 1000, TimeUnit.MILLISECONDS); + } + + + public void init() throws Exception { + initSessionCleaner(); + initSessionAckContextCleaner(); + initDownStreamMsgContextCleaner(); + logger.info("ClientSessionGroupMapping inited......"); + } + + public void start() throws Exception { + logger.info("ClientSessionGroupMapping started......"); + } + + public void shutdown() throws Exception { + logger.info("begin to close sessions gracefully"); + sessionTable.values().parallelStream().forEach(itr -> { + try { + ProxyTcp2Client.serverGoodby2Client(itr, this); + } catch (Exception e) { + logger.error("say goodbye to session error! {}", itr, e); + } + }); + ThreadUtil.randomSleep(50); + logger.info("ClientSessionGroupMapping shutdown......"); + } + + public ConcurrentHashMap getSessionMap() { + return sessionTable; + } + + public ConcurrentHashMap getClientGroupMap() { + return clientGroupMap; + } + + public HashMap statDCNSystemInfo() { + HashMap result = new HashMap(); + if (!sessionTable.isEmpty()) { + for (Session session : sessionTable.values()) { + String key = session.getClient().getDcn() + "|" + session.getClient().getSubsystem(); + if (!result.containsKey(key)) { + result.put(key, new AtomicInteger(1)); + } else { + result.get(key).incrementAndGet(); + } + } + } + return result; + } + + public HashMap statDCNSystemInfoByPurpose(String purpose) { + HashMap result = new HashMap(); + if (!sessionTable.isEmpty()) { + for (Session session : sessionTable.values()) { + if(!StringUtils.equals(session.getClient().getPurpose(), purpose)) + continue; + + String key = session.getClient().getDcn() + "|" + session.getClient().getSubsystem()+ "|" + purpose; + if (!result.containsKey(key)) { + result.put(key, new AtomicInteger(1)); + } else { + result.get(key).incrementAndGet(); + } + } + } + return result; + } + + public Map> prepareProxyClientDistributionData(){ + Map> result = null; + + if(!clientGroupMap.isEmpty()){ + result = new HashMap<>(); + for(Map.Entry entry : clientGroupMap.entrySet()){ + Map map = new HashMap(); + map.put(ProxyConstants.PURPOSE_SUB,entry.getValue().getGroupConsumerSessions().size()); + map.put(ProxyConstants.PURPOSE_PUB,entry.getValue().getGroupProducerSessions().size()); + result.put(entry.getKey(), map); + } + } + + return result; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/dispatch/DownstreamDispatchStrategy.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/dispatch/DownstreamDispatchStrategy.java new file mode 100644 index 0000000000..04efce3d1d --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/dispatch/DownstreamDispatchStrategy.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/dispatch/DownstreamDispatchStrategy.java +package cn.webank.emesher.core.protocol.tcp.client.group.dispatch; + + +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +======== +package com.webank.runtime.core.protocol.tcp.client.group.dispatch; + + +import com.webank.runtime.core.protocol.tcp.client.session.Session; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/group/dispatch/DownstreamDispatchStrategy.java + +import java.util.Set; + +public interface DownstreamDispatchStrategy { + /** + * 选择一个SESSION + * @param group + * @param consumeSessions + * @return + */ + Session select(String group, String topic, Set consumeSessions); +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/dispatch/FreePriorityDispatchStrategy.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/dispatch/FreePriorityDispatchStrategy.java new file mode 100644 index 0000000000..ebe0e29a71 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/dispatch/FreePriorityDispatchStrategy.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/group/dispatch/FreePriorityDispatchStrategy.java +package cn.webank.emesher.core.protocol.tcp.client.group.dispatch; + +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +======== +package com.webank.runtime.core.protocol.tcp.client.group.dispatch; + +import com.webank.runtime.core.protocol.tcp.client.session.Session; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/group/dispatch/FreePriorityDispatchStrategy.java +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public class FreePriorityDispatchStrategy implements DownstreamDispatchStrategy { + + private static final Logger logger = LoggerFactory.getLogger(FreePriorityDispatchStrategy.class); + + @Override + public Session select(String group, String topic, Set groupConsumerSessions) { + if(CollectionUtils.isEmpty(groupConsumerSessions) + || StringUtils.isBlank(topic) + || StringUtils.isBlank(group)) { + return null; + } + + List filtered = new ArrayList(); + List canDownSessions = new ArrayList<>(); + for (Session session : groupConsumerSessions) { + if (!session.isAvailable(topic)) { + continue; + } + if(session.isDownStreamBusy()){ + canDownSessions.add(session); + continue; + } + filtered.add(session); + } + + if (CollectionUtils.isEmpty(filtered)) { + if(CollectionUtils.isEmpty(canDownSessions)){ + logger.warn("all sessions can't downstream msg"); + return null; + }else{ + logger.warn("all sessions are busy,group:{},topic:{}",group,topic); + filtered.addAll(canDownSessions); + } + } + + Collections.shuffle(filtered); + Session session = filtered.get(0); + return session; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/Session.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/Session.java new file mode 100644 index 0000000000..30ac74beab --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/Session.java @@ -0,0 +1,367 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/Session.java +package cn.webank.emesher.core.protocol.tcp.client.session; + +import cn.webank.emesher.configuration.AccessConfiguration; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.group.ClientGroupWrapper; +import cn.webank.emesher.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import cn.webank.emesher.core.protocol.tcp.client.session.push.SessionPusher; +import cn.webank.emesher.core.protocol.tcp.client.session.send.ProxyTcpSendResult; +import cn.webank.emesher.core.protocol.tcp.client.session.send.SessionSender; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import cn.webank.emesher.util.Utils; +======== +package com.webank.runtime.core.protocol.tcp.client.session; + +import com.webank.runtime.configuration.AccessConfiguration; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.tcp.client.group.ClientGroupWrapper; +import com.webank.runtime.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import com.webank.runtime.core.protocol.tcp.client.session.push.SessionPusher; +import com.webank.runtime.core.protocol.tcp.client.session.send.ProxyTcpSendResult; +import com.webank.runtime.core.protocol.tcp.client.session.send.SessionSender; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +import com.webank.runtime.util.Utils; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/Session.java +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.ref.WeakReference; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.concurrent.locks.ReentrantLock; + +import static cn.webank.eventmesh.common.protocol.tcp.Command.LISTEN_RESPONSE; + +public class Session { + + protected final Logger messageLogger = LoggerFactory.getLogger("message"); + + private final Logger subscribeLogger = LoggerFactory.getLogger("subscribeLogger"); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private UserAgent client; + + private InetSocketAddress remoteAddress; + + protected ChannelHandlerContext context; + + private WeakReference clientGroupWrapper; + + private AccessConfiguration accessConfiguration; + + private SessionPusher pusher; + + private SessionSender sender; + + private long createTime = System.currentTimeMillis(); + + private long lastHeartbeatTime = System.currentTimeMillis(); + + private long isolateTime = 0; + + private SessionContext sessionContext = new SessionContext(this); + + private boolean listenRspSend = false; + + private ReentrantLock listenRspLock = new ReentrantLock(); + + private String listenRequestSeq = null; + + protected SessionState sessionState = SessionState.CREATED; + + public InetSocketAddress getRemoteAddress() { + return remoteAddress; + } + + public void setRemoteAddress(InetSocketAddress remoteAddress) { + this.remoteAddress = remoteAddress; + } + + public long getLastHeartbeatTime() { + return lastHeartbeatTime; + } + + public void notifyHeartbeat(long heartbeatTime) throws Exception { + this.lastHeartbeatTime = heartbeatTime; + } + + public SessionState getSessionState() { + return sessionState; + } + + public void setSessionState(SessionState sessionState) { + this.sessionState = sessionState; + } + + public void setClient(UserAgent client) { + this.client = client; + } + + public SessionPusher getPusher() { + return pusher; + } + + public void setPusher(SessionPusher pusher) { + this.pusher = pusher; + } + + public SessionSender getSender() { + return sender; + } + + public void setSender(SessionSender sender) { + this.sender = sender; + } + + public void setLastHeartbeatTime(long lastHeartbeatTime) { + this.lastHeartbeatTime = lastHeartbeatTime; + } + + public SessionContext getSessionContext() { + return sessionContext; + } + + public void setSessionContext(SessionContext sessionContext) { + this.sessionContext = sessionContext; + } + + public ChannelHandlerContext getContext() { + return context; + } + + public void setContext(ChannelHandlerContext context) { + this.context = context; + } + + public UserAgent getClient() { + return client; + } + + public String getListenRequestSeq() { + return listenRequestSeq; + } + + public void setListenRequestSeq(String listenRequestSeq) { + this.listenRequestSeq = listenRequestSeq; + } + + public void subscribe(List topics) throws Exception { + for (String topic : topics) { + sessionContext.subscribeTopics.putIfAbsent(topic, topic); + clientGroupWrapper.get().subscribe(topic); + + clientGroupWrapper.get().getDefibusProducer().getDefaultMQProducer().getDefaultMQProducerImpl() + .getmQClientFactory().getMQClientAPIImpl().getDefaultTopicRouteInfoFromNameServer(topic, + ProxyConstants.DEFAULT_TIME_OUT_MILLS); + + clientGroupWrapper.get().addSubscription(topic, this); + subscribeLogger.info("subscribe|succeed|topic={}|user={}", topic, client); + } + } + + public void unsubscribe(List topics) throws Exception { + for (String topic : topics) { + sessionContext.subscribeTopics.remove(topic); + clientGroupWrapper.get().removeSubscription(topic, this); + + if (!clientGroupWrapper.get().hasSubscription(topic)) { + clientGroupWrapper.get().unsubscribe(topic); + subscribeLogger.info("unSubscribe|succeed|topic={}|lastUser={}", topic, client); + } + } + } + + public ProxyTcpSendResult upstreamMsg(Header header, Message msg, SendCallback sendCallback, long startTime, long taskExecuteTime) { + sessionContext.sendTopics.putIfAbsent(msg.getTopic(), msg.getTopic()); + return sender.send(header, msg, sendCallback, startTime, taskExecuteTime); + } + + public void downstreamMsg(DownStreamMsgContext downStreamMsgContext) { + long currTime = System.currentTimeMillis(); + trySendListenResponse(new Header(LISTEN_RESPONSE, OPStatus.SUCCESS.getCode(), "succeed", getListenRequestSeq()), currTime, currTime); + + pusher.push(downStreamMsgContext); + } + + public boolean isDownStreamBusy() { + return pusher.isBusy(); + } + + public boolean isCanDownStream() { + return pusher.isCanDownStream(); + } + + public boolean isIsolated(){ + return System.currentTimeMillis() < isolateTime; + } + + public void write2Client(final Package pkg) { + + try { + if (SessionState.CLOSED.equals(sessionState)) { + return; + } + context.writeAndFlush(pkg).addListener( + new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (!future.isSuccess()) { + messageLogger.error("write2Client fail, pkg[{}] session[{}]", pkg, this); + }else{ + clientGroupWrapper.get().getProxyTcpMonitor().getProxy2clientMsgNum().incrementAndGet(); + } + } + } + ); + } catch (Exception e) { + logger.error("exception while write2Client", e); + } + } + + /** + * ACK MSG + * + * @param seq + */ + public void ackMsg(String seq) { + logger.info("ackMsg start,seq:{}", seq); + pusher.getPushContext().ackMsg(seq); + logger.info("ackMsg end,seq:{}", seq); + } + + @Override + public String toString() { + return "Session{" + + "group=" + clientGroupWrapper.get().getGroupName() + + ",remoteAddr=" + RemotingHelper.parseSocketAddressAddr(remoteAddress) + + ",client=" + client + + ",sessionState=" + sessionState + + ",sessionContext=" + sessionContext + + ",pusher=" + pusher + + ",sender=" + sender + + ",createTime=" + DateFormatUtils.format(createTime, ProxyConstants.DATE_FORMAT) + + ",lastHeartbeatTime=" + DateFormatUtils.format(lastHeartbeatTime, ProxyConstants.DATE_FORMAT) + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Session session = (Session) o; + if (client != null ? !client.equals(session.client) : session.client != null) { + return false; + } + if (context != null ? !context.equals(session.context) : session.context != null) { + return false; + } + if (sessionState != null ? !sessionState.equals(session.sessionState) : session.sessionState != null) { + return false; + } + return true; + } + + public WeakReference getClientGroupWrapper() { + return clientGroupWrapper; + } + + public void setClientGroupWrapper(WeakReference clientGroupWrapper) { + this.clientGroupWrapper = clientGroupWrapper; + } + + public Session(UserAgent client, ChannelHandlerContext context, AccessConfiguration accessConfiguration) { + this.client = client; + this.context = context; + this.accessConfiguration = accessConfiguration; + this.remoteAddress = (InetSocketAddress) context.channel().remoteAddress(); + this.sender = new SessionSender(this); + this.pusher = new SessionPusher(this); + } + + public AccessConfiguration getAccessConfiguration() { + return accessConfiguration; + } + + public void setAccessConfiguration(AccessConfiguration accessConfiguration) { + this.accessConfiguration = accessConfiguration; + } + + public void trySendListenResponse(Header header, long startTime, long taskExecuteTime) { + if (!listenRspSend) { + if (listenRspLock.tryLock()) { + if (!listenRspSend) { + if (header == null) { + header = new Header(LISTEN_RESPONSE, OPStatus.SUCCESS.getCode(), "succeed", null); + } + Package msg = new Package(); + msg.setHeader(header); + + //TODO startTime 修改了 + Utils.writeAndFlush(msg, startTime, taskExecuteTime, context, this); + listenRspSend = true; + } + listenRspLock.unlock(); + } + } + } + + public long getIsolateTime() { + return isolateTime; + } + + public void setIsolateTime(long isolateTime) { + this.isolateTime = isolateTime; + } + + public boolean isAvailable(String topic){ + if(SessionState.CLOSED == sessionState){ + logger.warn("session is not available because session has been closed"); + return false; + } + + if(!sessionContext.subscribeTopics.containsKey(topic)){ + logger.warn("session is not available because session has not subscribe topic:{}",topic); + return false; + } + if(isIsolated()){ + logger.warn("session is not available because session is isolated,isolateTime:{}",isolateTime); + return false; + } + return true; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/SessionContext.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/SessionContext.java new file mode 100644 index 0000000000..800977f9ce --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/SessionContext.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/SessionContext.java +package cn.webank.emesher.core.protocol.tcp.client.session; + +import cn.webank.emesher.constants.ProxyConstants; +======== +package com.webank.runtime.core.protocol.tcp.client.session; + +import com.webank.runtime.constants.ProxyConstants; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/SessionContext.java +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.concurrent.ConcurrentHashMap; + +public class SessionContext { + + private Session session; + + public ConcurrentHashMap sendTopics = new ConcurrentHashMap(); + + public ConcurrentHashMap subscribeTopics = new ConcurrentHashMap(); + + public long createTime = System.currentTimeMillis(); + + public SessionContext(Session session) { + this.session = session; + } + + @Override + public String toString() { + return "SessionContext{subscribeTopics=" + subscribeTopics.keySet() + + ",sendTopics=" + sendTopics.keySet() + + ",createTime=" + DateFormatUtils.format(createTime, ProxyConstants.DATE_FORMAT) + "}"; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/SessionState.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/SessionState.java new file mode 100644 index 0000000000..1292b83813 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/SessionState.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/SessionState.java +package cn.webank.emesher.core.protocol.tcp.client.session; +======== +package com.webank.runtime.core.protocol.tcp.client.session; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/SessionState.java + +public enum SessionState { + CREATED, + RUNNING, + CLOSED +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/ClientAckContext.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/ClientAckContext.java new file mode 100644 index 0000000000..5d383b7e2c --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/ClientAckContext.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/ClientAckContext.java +package cn.webank.emesher.core.protocol.tcp.client.session.push; + +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.defibus.consumer.DeFiBusPushConsumer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.util.ProxyUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyContext; +======== +package com.webank.runtime.core.protocol.tcp.client.session.push; + +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.defibus.consumer.DeFiBusPushConsumer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.plugin.MQConsumerWrapper; +import com.webank.runtime.util.ProxyUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import com.webank.runtime.patch.ProxyConsumeConcurrentlyContext; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/push/ClientAckContext.java +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageService; +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class ClientAckContext { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private String seq; + + private ConsumeMessageConcurrentlyContext context; + + private long createTime; + + private long expireTime; + + private List msgs; + + private DeFiBusPushConsumer consumer; + + public ClientAckContext(String seq, ConsumeMessageConcurrentlyContext context, List msgs, DeFiBusPushConsumer consumer) { + this.seq = seq; + this.context = context; + this.msgs = msgs; + this.consumer = consumer; + this.createTime = System.currentTimeMillis(); + this.expireTime = System.currentTimeMillis() + Long.valueOf(msgs.get(0).getProperty(DeFiBusConstant.PROPERTY_MESSAGE_TTL)); + } + + public boolean isExpire() { + return System.currentTimeMillis() >= expireTime; + } + + public String getSeq() { + return seq; + } + + public void setSeq(String seq) { + this.seq = seq; + } + + public ConsumeMessageConcurrentlyContext getContext() { + return context; + } + + public void setContext(ConsumeMessageConcurrentlyContext context) { + this.context = context; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public List getMsgs() { + return msgs; + } + + public void setMsgs(List msgs) { + this.msgs = msgs; + } + + public long getExpireTime() { + return expireTime; + } + + public void setExpireTime(long expireTime) { + this.expireTime = expireTime; + } + + public DeFiBusPushConsumer getConsumer() { + return consumer; + } + + public void ackMsg() { + if (consumer != null && context != null && msgs != null) { + ConsumeMessageService consumeMessageService = consumer.getDefaultMQPushConsumer().getDefaultMQPushConsumerImpl().getConsumeMessageService(); + ((ConsumeMessageConcurrentlyService)consumeMessageService).updateOffset(msgs, context); + logger.info("ackMsg topic:{}, bizSeq:{}", msgs.get(0).getTopic(), ProxyUtil.getMessageBizSeq(msgs.get(0))); + }else{ + logger.warn("ackMsg failed,consumer is null:{}, context is null:{} , msgs is null:{}",consumer == null, context == null, msgs == null); + } + } + + @Override + public String toString() { + return "ClientAckContext{" + + ",seq=" + seq + + ",consumer=" + consumer.getDefaultMQPushConsumer().getMessageModel() + + ",consumerGroup=" + consumer.getDefaultMQPushConsumer().getConsumerGroup() + + ",topic=" + (CollectionUtils.size(msgs) > 0 ? msgs.get(0).getTopic() : null) + + ",createTime=" + DateFormatUtils.format(createTime, ProxyConstants.DATE_FORMAT) + + ",expireTime=" + DateFormatUtils.format(expireTime, ProxyConstants.DATE_FORMAT) + '}'; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/DownStreamMsgContext.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/DownStreamMsgContext.java new file mode 100644 index 0000000000..d071b2e21a --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/DownStreamMsgContext.java @@ -0,0 +1,140 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/DownStreamMsgContext.java +package cn.webank.emesher.core.protocol.tcp.client.session.push; + +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.defibus.consumer.DeFiBusPushConsumer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.emesher.util.ServerGlobal; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyContext; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageService; +======== +package com.webank.runtime.core.protocol.tcp.client.session.push; + +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.plugin.MQConsumerWrapper; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.runtime.util.ServerGlobal; +import org.apache.commons.lang3.time.DateFormatUtils; +import com.webank.runtime.patch.ProxyConsumeConcurrentlyContext; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/push/DownStreamMsgContext.java +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +public class DownStreamMsgContext implements Delayed { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + public String seq; + + public MessageExt msgExt; + + public Session session; + + public ConsumeMessageConcurrentlyContext consumeConcurrentlyContext; + + public DeFiBusPushConsumer consumer; + + public int retryTimes; + + private long executeTime; + + public long lastPushTime; + + private long createTime; + + private long expireTime; + + public boolean msgFromOtherProxy; + + public DownStreamMsgContext(MessageExt msgExt, Session session, DeFiBusPushConsumer consumer, ConsumeMessageConcurrentlyContext consumeConcurrentlyContext, boolean msgFromOtherProxy) { + this.seq = String.valueOf(ServerGlobal.getInstance().getMsgCounter().incrementAndGet()); + this.msgExt = msgExt; + this.session = session; + this.retryTimes = 0; + this.consumer = consumer; + this.consumeConcurrentlyContext = consumeConcurrentlyContext; + this.lastPushTime = System.currentTimeMillis(); + this.executeTime = System.currentTimeMillis(); + this.createTime = System.currentTimeMillis(); + this.expireTime = System.currentTimeMillis() + Long.valueOf(msgExt.getProperty(DeFiBusConstant.PROPERTY_MESSAGE_TTL)); + this.msgFromOtherProxy = msgFromOtherProxy; + } + + public boolean isExpire() { + return System.currentTimeMillis() >= expireTime; + } + + public void ackMsg() { + if (consumer != null && consumeConcurrentlyContext != null && msgExt != null) { + List msgs = new ArrayList(); + msgs.add(msgExt); + ConsumeMessageService consumeMessageService = consumer.getDefaultMQPushConsumer().getDefaultMQPushConsumerImpl().getConsumeMessageService(); + ((ConsumeMessageConcurrentlyService)consumeMessageService).updateOffset(msgs, consumeConcurrentlyContext); + logger.info("ackMsg topic:{}, bizSeq:{}", msgs.get(0).getTopic(), msgs.get(0).getKeys()); + }else{ + logger.warn("ackMsg failed,consumer is null:{}, context is null:{} , msgs is null:{}",consumer == null, consumeConcurrentlyContext == null, msgExt == null); + } + } + + public void delay(long delay) { + this.executeTime = System.currentTimeMillis() + (retryTimes + 1) * delay; + } + + @Override + public String toString() { + return "DownStreamMsgContext{" + + ",seq=" + seq + + ",client=" + session.getClient() + + ",retryTimes=" + retryTimes + + ",consumer=" + consumer.getDefaultMQPushConsumer().getMessageModel() + + ",consumerGroup=" + consumer.getDefaultMQPushConsumer().getConsumerGroup() + + ",topic=" + msgExt.getTopic() + + ",createTime=" + DateFormatUtils.format(createTime, ProxyConstants.DATE_FORMAT) + + ",executeTime=" + DateFormatUtils.format(executeTime, ProxyConstants.DATE_FORMAT) + + ",lastPushTime=" + DateFormatUtils.format(lastPushTime, ProxyConstants.DATE_FORMAT) + '}'; + } + + @Override + public int compareTo(Delayed delayed) { + DownStreamMsgContext context = (DownStreamMsgContext) delayed; + if (this.executeTime > context.executeTime) { + return 1; + } else if (this.executeTime == context.executeTime) { + return 0; + } else { + return -1; + } + } + + @Override + public long getDelay(TimeUnit unit) { + return unit.convert(this.executeTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/PushContext.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/PushContext.java new file mode 100644 index 0000000000..5a89d853f4 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/PushContext.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/PushContext.java +package cn.webank.emesher.core.protocol.tcp.client.session.push; + +import cn.webank.defibus.consumer.DeFiBusPushConsumer; +import cn.webank.emesher.constants.ProxyConstants; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyContext; +======== +package com.webank.runtime.core.protocol.tcp.client.session.push; + +import com.webank.defibus.consumer.DeFiBusPushConsumer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.plugin.MQConsumerWrapper; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import com.webank.runtime.patch.ProxyConsumeConcurrentlyContext; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/push/PushContext.java +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +public class PushContext { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + private SessionPusher sessionPusher; + + public AtomicLong deliveredMsgsCount = new AtomicLong(0); + + public AtomicLong ackedMsgsCount = new AtomicLong(0); + + public AtomicLong deliverFailMsgsCount = new AtomicLong(0); + + private ConcurrentHashMap unAckMsg = new ConcurrentHashMap(); + + private long createTime = System.currentTimeMillis(); + + public PushContext(SessionPusher sessionPusher) { + this.sessionPusher = sessionPusher; + } + + public void deliveredMsgCount() { + deliveredMsgsCount.incrementAndGet(); + } + + public void deliverFailMsgCount() { + deliverFailMsgsCount.incrementAndGet(); + } + + public void unAckMsg(String seq, List msg, ConsumeMessageConcurrentlyContext context, DeFiBusPushConsumer consumer) { + ClientAckContext ackContext = new ClientAckContext(seq,context, msg, consumer); + unAckMsg.put(seq, ackContext); + logger.info("put msg in unAckMsg,seq:{},unAckMsgSize:{}", seq, getTotalUnackMsgs()); + } + + public int getTotalUnackMsgs() { + return unAckMsg.size(); + } + + public void ackMsg(String seq) { + if (unAckMsg.containsKey(seq)) { + unAckMsg.get(seq).ackMsg(); + unAckMsg.remove(seq); + ackedMsgsCount.incrementAndGet(); + }else{ + logger.warn("ackMsg failed,the seq:{} is not in unAckMsg map", seq); + } + } + + public ConcurrentHashMap getUnAckMsg() { + return unAckMsg; + } + + @Override + public String toString() { + return "PushContext{" + + "deliveredMsgsCount=" + deliveredMsgsCount.longValue() + + ",deliverFailCount=" + deliverFailMsgsCount.longValue() + + ",ackedMsgsCount=" + ackedMsgsCount.longValue() + + ",unAckMsg=" + CollectionUtils.size(unAckMsg) + + ",createTime=" + DateFormatUtils.format(createTime, ProxyConstants.DATE_FORMAT) + '}'; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/SessionPusher.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/SessionPusher.java new file mode 100644 index 0000000000..d3a9710eb2 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/SessionPusher.java @@ -0,0 +1,156 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/SessionPusher.java +package cn.webank.emesher.core.protocol.tcp.client.session.push; + +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.eventmesh.common.protocol.tcp.AccessMessage; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.core.protocol.tcp.client.session.push; + +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.eventmesh.common.protocol.tcp.AccessMessage; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/push/SessionPusher.java +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class SessionPusher { + + private final Logger messageLogger = LoggerFactory.getLogger("message"); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private Integer unack; + + private PushContext pushContext = new PushContext(this); + + public PushContext getPushContext() { + return pushContext; + } + + public boolean isBusy() { + return pushContext.getTotalUnackMsgs() >= Math.floor(3 * unack / 4); + } + + public boolean isCanDownStream() { + return pushContext.getTotalUnackMsgs() < unack; + } + + public void setPushContext(PushContext pushContext) { + this.pushContext = pushContext; + } + + private Session session; + + public SessionPusher(Session session) { + this.session = session; + unack = (0 == session.getClient().getUnack()) ? session.getAccessConfiguration().proxyTcpSessionDownstreamUnackSize : session.getClient().getUnack(); + } + + @Override + public String toString() { + return "SessionPusher{unack=" + unack + + ",busy=" + isBusy() + + ",canDownStream=" + isCanDownStream() + + ",pushContext=" + pushContext + "}"; + } + + public void push(final DownStreamMsgContext downStreamMsgContext) { + Command cmd; + if (ProxyUtil.isBroadcast(downStreamMsgContext.msgExt.getTopic())) { + cmd = Command.BROADCAST_MESSAGE_TO_CLIENT; + } else if (ProxyUtil.isService(downStreamMsgContext.msgExt.getTopic())) { + cmd = Command.REQUEST_TO_CLIENT; + } else { + cmd = Command.ASYNC_MESSAGE_TO_CLIENT; + } + + Package pkg = new Package(); + downStreamMsgContext.msgExt.putUserProperty(ProxyConstants.REQ_PROXY2C_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + AccessMessage body = null; + int retCode = 0; + String retMsg = null; + try { + body = ProxyUtil.encodeMessage(downStreamMsgContext.msgExt); + pkg.setBody(body); + pkg.setHeader(new Header(cmd, OPStatus.SUCCESS.getCode(), null, downStreamMsgContext.seq)); + messageLogger.info("pkg|mq2proxy|cmd={}|mqMsg={}|user={}", cmd, ProxyUtil.printMqMessage(body), session.getClient()); + } catch (Exception e) { + pkg.setHeader(new Header(cmd, OPStatus.FAIL.getCode(), e.getStackTrace().toString(), downStreamMsgContext.seq)); + retCode = -1; + retMsg = e.toString(); + } finally { + session.getClientGroupWrapper().get().getProxyTcpMonitor().getProxy2clientMsgNum().incrementAndGet(); + pushContext.deliveredMsgCount(); + session.getContext().writeAndFlush(pkg).addListener( + new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (!future.isSuccess()) { + logger.error("downstreamMsg fail,seq:{}, retryTimes:{}, msg:{}", downStreamMsgContext.seq, downStreamMsgContext.retryTimes, downStreamMsgContext.msgExt); + pushContext.deliverFailMsgCount(); + + //how long to isolate client when push fail + long isolateTime = System.currentTimeMillis() + session.getAccessConfiguration().proxyTcpPushFailIsolateTimeInMills; + session.setIsolateTime(isolateTime); + logger.warn("isolate client:{},isolateTime:{}", session.getClient(), isolateTime); + + //retry + long delayTime = ProxyUtil.isService(downStreamMsgContext.msgExt.getTopic()) ? 0 : session.getAccessConfiguration().proxyTcpMsgRetryDelayInMills; + downStreamMsgContext.delay(delayTime); + session.getClientGroupWrapper().get().getProxyTcpRetryer().pushRetry(downStreamMsgContext); + } else { + pushContext.deliveredMsgCount(); + logger.info("downstreamMsg success,seq:{}, retryTimes:{}, bizSeq:{}", downStreamMsgContext.seq,downStreamMsgContext.retryTimes, ProxyUtil.getMessageBizSeq(downStreamMsgContext.msgExt)); + List msgExts = new ArrayList(); + msgExts.add(downStreamMsgContext.msgExt); + pushContext.unAckMsg(downStreamMsgContext.seq, + msgExts, + downStreamMsgContext.consumeConcurrentlyContext, + downStreamMsgContext.consumer); + + session.getClientGroupWrapper().get().getDownstreamMap().remove(downStreamMsgContext.seq); + if(session.isIsolated()){ + logger.info("cancel isolated,client:{}", session.getClient()); + session.setIsolateTime(System.currentTimeMillis()); + } + } + } + } + ); + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/retry/ProxyTcpRetryer.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/retry/ProxyTcpRetryer.java new file mode 100644 index 0000000000..f670b31f77 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/retry/ProxyTcpRetryer.java @@ -0,0 +1,225 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/push/retry/ProxyTcpRetryer.java +package cn.webank.emesher.core.protocol.tcp.client.session.push.retry; + +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.defibus.common.message.DeFiBusMessageConst; +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.emesher.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import cn.webank.emesher.threads.ProxyThreadFactoryImpl; +import cn.webank.emesher.threads.ThreadPoolHelper; +import cn.webank.emesher.util.ProxyUtil; +======== +package com.webank.runtime.core.protocol.tcp.client.session.push.retry; + +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.defibus.common.message.DeFiBusMessageConst; +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.runtime.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import com.webank.runtime.util.ProxyThreadFactoryImpl; +import com.webank.runtime.util.ProxyUtil; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/push/retry/ProxyTcpRetryer.java +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageService; +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class ProxyTcpRetryer { + + public static Logger logger = LoggerFactory.getLogger(ProxyTcpRetryer.class); + + private ProxyTCPServer proxyTCPServer; + + private DelayQueue retrys = new DelayQueue(); + + private ThreadPoolExecutor pool = new ThreadPoolExecutor(3, + 3, + 60000, + TimeUnit.MILLISECONDS, new ArrayBlockingQueue(1000), + new ProxyThreadFactoryImpl("proxy-tcp-retry",true), + new ThreadPoolExecutor.AbortPolicy()); + + private Thread dispatcher; + + public ProxyTcpRetryer(ProxyTCPServer proxyTCPServer) { + this.proxyTCPServer = proxyTCPServer; + } + + public ProxyTCPServer getProxyTCPServer() { + return proxyTCPServer; + } + + public void setProxyTCPServer(ProxyTCPServer proxyTCPServer) { + this.proxyTCPServer = proxyTCPServer; + } + + public void pushRetry(DownStreamMsgContext downStreamMsgContext) { + if (retrys.size() >= proxyTCPServer.getAccessConfiguration().proxyTcpMsgRetryQueueSize) { + logger.error("pushRetry fail,retrys is too much,allow max retryQueueSize:{}, retryTimes:{}, seq:{}, bizSeq:{}", + proxyTCPServer.getAccessConfiguration().proxyTcpMsgRetryQueueSize, downStreamMsgContext.retryTimes, + downStreamMsgContext.seq, ProxyUtil.getMessageBizSeq(downStreamMsgContext.msgExt)); + return; + } + + int maxRetryTimes = ProxyUtil.isService(downStreamMsgContext.msgExt.getTopic()) ? 1 : proxyTCPServer.getAccessConfiguration().proxyTcpMsgRetryTimes; + if (downStreamMsgContext.retryTimes >= maxRetryTimes) { + logger.warn("pushRetry fail,retry over maxRetryTimes:{}, retryTimes:{}, seq:{}, bizSeq:{}", maxRetryTimes, downStreamMsgContext.retryTimes, + downStreamMsgContext.seq, ProxyUtil.getMessageBizSeq(downStreamMsgContext.msgExt)); + return; + } + + retrys.offer(downStreamMsgContext); + logger.info("pushRetry success,seq:{}, retryTimes:{}, bizSeq:{}",downStreamMsgContext.seq, downStreamMsgContext.retryTimes, ProxyUtil.getMessageBizSeq(downStreamMsgContext.msgExt)); + } + + public void init() { + dispatcher = new Thread(new Runnable() { + @Override + public void run() { + try { + DownStreamMsgContext downStreamMsgContext = null; + while ((downStreamMsgContext = retrys.take()) != null) { + final DownStreamMsgContext finalDownStreamMsgContext = downStreamMsgContext; + pool.execute(() -> { + retryHandle(finalDownStreamMsgContext); + }); + } + } catch (Exception e) { + logger.error("retry-dispatcher error!", e); + } + } + }, "retry-dispatcher"); + dispatcher.setDaemon(true); + logger.info("ProxyTcpRetryer inited......"); + } + + private void retryHandle(DownStreamMsgContext downStreamMsgContext){ + try { + logger.info("retry downStream msg start,seq:{},retryTimes:{},bizSeq:{}",downStreamMsgContext.seq, downStreamMsgContext.retryTimes, ProxyUtil.getMessageBizSeq(downStreamMsgContext.msgExt)); + + if(isRetryMsgTimeout(downStreamMsgContext)) + return; + + downStreamMsgContext.retryTimes++; + downStreamMsgContext.lastPushTime = System.currentTimeMillis(); + + Session rechoosen = null; + if(!ProxyUtil.isBroadcast(downStreamMsgContext.msgExt.getTopic())){ + rechoosen = downStreamMsgContext.session.getClientGroupWrapper() + .get().getDownstreamDispatchStrategy().select(downStreamMsgContext.session.getClientGroupWrapper().get().getGroupName() + , downStreamMsgContext.msgExt.getTopic() + , downStreamMsgContext.session.getClientGroupWrapper().get().getGroupConsumerSessions()); + }else{ + rechoosen = downStreamMsgContext.session; + } + + + if(rechoosen == null){ + logger.warn("retry, found no session to downstream msg,seq:{}, retryTimes:{}, bizSeq:{}", downStreamMsgContext.seq, downStreamMsgContext.retryTimes, ProxyUtil.getMessageBizSeq(downStreamMsgContext.msgExt)); + +// //需要手动ack掉没有下发成功的消息 +// proxyAckMsg(downStreamMsgContext); + +// //重试找不到下发session不再回发broker或者重试其它proxy +// String bizSeqNo = finalDownStreamMsgContext.msgExt.getKeys(); +// String uniqueId = MapUtils.getString(finalDownStreamMsgContext.msgExt.getProperties(), WeMQConstant.RMB_UNIQ_ID, ""); +// if(weMQProxyTCPServer.getAccessConfiguration().proxyTcpSendBackEnabled){ +// sendMsgBackToBroker(finalDownStreamMsgContext.msgExt, bizSeqNo, uniqueId); +// }else{ +// //TODO 将消息推给其它proxy,待定 +// sendMsgToOtherProxy(finalDownStreamMsgContext.msgExt, bizSeqNo, uniqueId); +// } + }else { + downStreamMsgContext.session = rechoosen; + + if (rechoosen.isCanDownStream()) { + rechoosen.downstreamMsg(downStreamMsgContext); + logger.info("retry downStream msg end,seq:{},retryTimes:{},bizSeq:{}",downStreamMsgContext.seq, downStreamMsgContext.retryTimes, ProxyUtil.getMessageBizSeq(downStreamMsgContext.msgExt)); + }else{ + logger.warn("session is busy,push retry again,seq:{}, session:{}, bizSeq:{}", downStreamMsgContext.seq, downStreamMsgContext.session.getClient(), ProxyUtil.getMessageBizSeq(downStreamMsgContext.msgExt)); + long delayTime = ProxyUtil.isService(downStreamMsgContext.msgExt.getTopic()) ? 0 : proxyTCPServer.getAccessConfiguration().proxyTcpMsgRetryDelayInMills; + downStreamMsgContext.delay(delayTime); + pushRetry(downStreamMsgContext); + } + } + } catch (Exception e) { + logger.error("retry-dispatcher error!", e); + } + } + + private boolean isRetryMsgTimeout(DownStreamMsgContext downStreamMsgContext){ + boolean flag =false; + long ttl = Long.valueOf(downStreamMsgContext.msgExt.getUserProperty(DeFiBusConstant.PROPERTY_MESSAGE_TTL)); + long storeTimestamp = downStreamMsgContext.msgExt.getStoreTimestamp(); + String leaveTimeStr = downStreamMsgContext.msgExt.getProperties().get(DeFiBusMessageConst.LEAVE_TIME); + long brokerCost = StringUtils.isNumeric(leaveTimeStr) ? Long.valueOf(leaveTimeStr) - storeTimestamp : 0; + + String arriveTimeStr = downStreamMsgContext.msgExt.getProperties().get(DeFiBusMessageConst.ARRIVE_TIME); + long accessCost = StringUtils.isNumeric(arriveTimeStr) ? System.currentTimeMillis() - Long.valueOf(arriveTimeStr) : 0; + double elapseTime = brokerCost + accessCost; + if (elapseTime >= ttl) { + logger.warn("discard the retry because timeout, seq:{}, retryTimes:{}, bizSeq:{}", downStreamMsgContext.seq, downStreamMsgContext.retryTimes, ProxyUtil.getMessageBizSeq(downStreamMsgContext.msgExt)); + flag = true; + proxyAckMsg(downStreamMsgContext); + } + return flag; + } + + public void start() throws Exception { + dispatcher.start(); + logger.info("ProxyTcpRetryer started......"); + } + + public void shutdown() { + pool.shutdown(); + logger.info("ProxyTcpRetryer shutdown......"); + } + + public int getRetrySize(){ + return retrys.size(); + } + + /** + * proxy ack msg + * + * @param downStreamMsgContext + */ + private void proxyAckMsg(DownStreamMsgContext downStreamMsgContext){ + List msgExts = new ArrayList(); + msgExts.add(downStreamMsgContext.msgExt); + logger.warn("proxyAckMsg topic:{}, seq:{}, bizSeq:{}",downStreamMsgContext.msgExt.getTopic(), downStreamMsgContext.seq, downStreamMsgContext.msgExt.getKeys()); + ConsumeMessageService consumeMessageService = downStreamMsgContext.consumer.getDefaultMQPushConsumer().getDefaultMQPushConsumerImpl().getConsumeMessageService(); + ((ConsumeMessageConcurrentlyService)consumeMessageService).updateOffset(msgExts, downStreamMsgContext.consumeConcurrentlyContext); + } + + public void printRetryThreadPoolState(){ + ThreadPoolHelper.printState(pool); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/ProxyTcpSendResult.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/ProxyTcpSendResult.java new file mode 100644 index 0000000000..14b2539448 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/ProxyTcpSendResult.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/ProxyTcpSendResult.java +package cn.webank.emesher.core.protocol.tcp.client.session.send; +======== +package com.webank.runtime.core.protocol.tcp.client.session.send; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/send/ProxyTcpSendResult.java + +public class ProxyTcpSendResult { + + private String seq; + + private ProxyTcpSendStatus sendStatus; + + private String detail; + + public ProxyTcpSendResult(String seq, ProxyTcpSendStatus sendStatus, String detail) { + this.seq = seq; + this.sendStatus = sendStatus; + this.detail = detail; + } + + public String getSeq() { + return seq; + } + + public ProxyTcpSendStatus getSendStatus() { + return sendStatus; + } + + public String getDetail() { + return detail; + } + + @Override + public String toString() { + return "ProxyTcpSendResult{seq=" + seq + + ",sendStatus=" + sendStatus + + ",detail=" + detail + "}"; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/ProxyTcpSendStatus.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/ProxyTcpSendStatus.java new file mode 100644 index 0000000000..e0a0ac3292 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/ProxyTcpSendStatus.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/ProxyTcpSendStatus.java +package cn.webank.emesher.core.protocol.tcp.client.session.send; +======== +package com.webank.runtime.core.protocol.tcp.client.session.send; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/send/ProxyTcpSendStatus.java + +public enum ProxyTcpSendStatus { + SUCCESS, + SEND_TOO_FAST, + OTHER_EXCEPTION; +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/SessionSender.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/SessionSender.java new file mode 100644 index 0000000000..ccd59b69e0 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/SessionSender.java @@ -0,0 +1,175 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/SessionSender.java +package cn.webank.emesher.core.protocol.tcp.client.session.send; + +import cn.webank.defibus.client.impl.producer.RRCallback; +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.emesher.util.ProxyUtil; +import cn.webank.emesher.util.Utils; +======== +package com.webank.runtime.core.protocol.tcp.client.session.send; + +import com.webank.defibus.client.impl.producer.RRCallback; +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.runtime.util.ProxyUtil; +import com.webank.runtime.util.Utils; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/send/SessionSender.java +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +public class SessionSender { + + private final Logger messageLogger = LoggerFactory.getLogger("message"); + private final Logger logger = LoggerFactory.getLogger(SessionSender.class); + + private Session session; + + public long createTime = System.currentTimeMillis(); + + public AtomicLong upMsgs = new AtomicLong(0); + + public AtomicLong failMsgCount = new AtomicLong(0); + + private static final int TRY_PERMIT_TIME_OUT = 5; + + @Override + public String toString() { + return "SessionSender{upstreamBuff=" + upstreamBuff.availablePermits() + + ",upMsgs=" + upMsgs.longValue() + + ",failMsgCount=" + failMsgCount.longValue() + + ",createTime=" + DateFormatUtils.format(createTime, ProxyConstants.DATE_FORMAT) + '}'; + } + + public Semaphore getUpstreamBuff() { + return upstreamBuff; + } + + private Semaphore upstreamBuff ; + + public SessionSender(Session session) { + this.session = session; + this.upstreamBuff = new Semaphore(session.getAccessConfiguration().proxyTcpSessionUpstreamBufferSize); + } + + public ProxyTcpSendResult send(Header header, Message msg, SendCallback sendCallback, long startTime, long taskExecuteTime) { + try { + if (upstreamBuff.tryAcquire(TRY_PERMIT_TIME_OUT, TimeUnit.MILLISECONDS)) { + upMsgs.incrementAndGet(); + UpStreamMsgContext upStreamMsgContext = null; + Command cmd = header.getCommand(); + if (Command.REQUEST_TO_SERVER == cmd) { + long ttl = msg.getProperty(DeFiBusConstant.PROPERTY_MESSAGE_TTL) != null ? Long.valueOf(msg.getProperty + (DeFiBusConstant.PROPERTY_MESSAGE_TTL)) : ProxyConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS; + upStreamMsgContext = new UpStreamMsgContext(header.getSeq(), session, msg); + session.getClientGroupWrapper().get().request(upStreamMsgContext, sendCallback, initSyncRRCallback(header, startTime, taskExecuteTime), ttl); + } else if (Command.RESPONSE_TO_SERVER == cmd) { + String cluster = msg.getUserProperty(DeFiBusConstant.PROPERTY_MESSAGE_CLUSTER); + if (!StringUtils.isEmpty(cluster)) { + String replyTopic = DeFiBusConstant.RR_REPLY_TOPIC; + replyTopic = cluster + "-" + replyTopic; + msg.setTopic(replyTopic); + } + upStreamMsgContext = new UpStreamMsgContext(header.getSeq(), session, msg); + session.getClientGroupWrapper().get().reply(upStreamMsgContext); + upstreamBuff.release(); + } else { + upStreamMsgContext = new UpStreamMsgContext(header.getSeq(), session, msg); + session.getClientGroupWrapper().get().send(upStreamMsgContext, sendCallback); + } + + session.getClientGroupWrapper().get().getProxyTcpMonitor().getProxy2mqMsgNum().incrementAndGet(); + } else { + logger.warn("send too fast,session flow control,session:{}",session.getClient()); + return new ProxyTcpSendResult(header.getSeq(), ProxyTcpSendStatus.SEND_TOO_FAST, ProxyTcpSendStatus.SEND_TOO_FAST.name()); + } + } catch (Exception e) { + logger.warn("SessionSender send failed", e); + if(!(e instanceof InterruptedException)) { + upstreamBuff.release(); + } + failMsgCount.incrementAndGet(); + return new ProxyTcpSendResult(header.getSeq(), ProxyTcpSendStatus.OTHER_EXCEPTION, e.getCause().toString()); + } + return new ProxyTcpSendResult(header.getSeq(), ProxyTcpSendStatus.SUCCESS, ProxyTcpSendStatus.SUCCESS.name()); + } + + private RRCallback initSyncRRCallback(Header header, long startTime, long taskExecuteTime) { + return new RRCallback() { + @Override + public void onSuccess(Message msg) { + String seq = header.getSeq(); + if (msg instanceof MessageExt) { + msg.putUserProperty(ProxyConstants.BORN_TIMESTAMP, String.valueOf(((MessageExt) msg) + .getBornTimestamp())); + msg.putUserProperty(ProxyConstants.STORE_TIMESTAMP, String.valueOf(((MessageExt) msg) + .getStoreTimestamp())); + } + msg.putUserProperty(ProxyConstants.RSP_MQ2PROXY_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + msg.putUserProperty(ProxyConstants.RSP_RECEIVE_PROXY_IP, ProxyUtil.getLocalAddr()); + session.getClientGroupWrapper().get().getProxyTcpMonitor().getMq2proxyMsgNum().incrementAndGet(); + + Command cmd; + if (header.getCommand().equals(Command.REQUEST_TO_SERVER)) { + cmd = Command.RESPONSE_TO_CLIENT; + } else { + messageLogger.error("invalid message|messageHeader={}|msg={}", header, msg); + return; + } + Package pkg = new Package(); + pkg.setHeader(new Header(cmd, OPStatus.SUCCESS.getCode(), null, seq)); + msg.putUserProperty(ProxyConstants.RSP_PROXY2C_TIMESTAMP, String.valueOf(System.currentTimeMillis())); + try { + pkg.setBody(ProxyUtil.encodeMessage(msg)); + pkg.setHeader(new Header(cmd, OPStatus.SUCCESS.getCode(), null, seq)); + } catch (Exception e) { + pkg.setHeader(new Header(cmd, OPStatus.FAIL.getCode(), null, seq)); + } finally { + Utils.writeAndFlush(pkg, startTime, taskExecuteTime, session.getContext(), session); + //session.write2Client(pkg); + } + } + + @Override + public void onException(Throwable e) { + messageLogger.error("exception occur while sending RR message|user={}", session.getClient(), new Exception(e)); + } + }; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/UpStreamMsgContext.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/UpStreamMsgContext.java new file mode 100644 index 0000000000..7b0d9dc26c --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/UpStreamMsgContext.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/session/send/UpStreamMsgContext.java +package cn.webank.emesher.core.protocol.tcp.client.session.send; + +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +======== +package com.webank.runtime.core.protocol.tcp.client.session.send; + +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/session/send/UpStreamMsgContext.java +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.rocketmq.common.message.Message; + +public class UpStreamMsgContext { + + private Session session; + + private Message msg; + + private String seq; + + private long createTime = System.currentTimeMillis(); + + public UpStreamMsgContext(String seq, Session session, Message msg) { + this.seq = seq; + this.session = session; + this.msg = msg; + } + + public Session getSession() { + return session; + } + + public Message getMsg() { + return msg; + } + + public long getCreateTime() { + return createTime; + } + + @Override + public String toString() { + return "UpStreamMsgContext{seq=" + seq + + ",topic=" + msg.getTopic() + + ",client=" + session.getClient() + + ",createTime=" + DateFormatUtils.format(createTime, ProxyConstants.DATE_FORMAT) + "}"; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/AbstractTask.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/AbstractTask.java new file mode 100644 index 0000000000..8e37ad7065 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/AbstractTask.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/AbstractTask.java +package cn.webank.emesher.core.protocol.tcp.client.task; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.eventmesh.common.protocol.tcp.Package; +======== +package com.webank.runtime.core.protocol.tcp.client.task; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.eventmesh.common.protocol.tcp.Package; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/task/AbstractTask.java +import io.netty.channel.ChannelHandlerContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractTask implements Runnable { + + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + protected Package pkg; + protected ChannelHandlerContext ctx; + protected Session session; + protected long startTime; + protected ProxyTCPServer proxyTCPServer; + + public AbstractTask(Package pkg, ChannelHandlerContext ctx, long startTime, ProxyTCPServer proxyTCPServer) { + this.proxyTCPServer = proxyTCPServer; + this.pkg = pkg; + this.ctx = ctx; + this.session = proxyTCPServer.getClientSessionGroupMapping().getSession(ctx); + this.startTime = startTime; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/GoodbyeTask.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/GoodbyeTask.java new file mode 100644 index 0000000000..eb462351ee --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/GoodbyeTask.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/GoodbyeTask.java +package cn.webank.emesher.core.protocol.tcp.client.task; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.emesher.util.Utils; +======== +package com.webank.runtime.core.protocol.tcp.client.task; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.core.protocol.tcp.client.ProxyTcp2Client; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.runtime.util.Utils; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/task/GoodbyeTask.java +import io.netty.channel.ChannelHandlerContext; + +import static cn.webank.emesher.core.protocol.tcp.client.ProxyTcp2Client.closeSessionIfTimeout; +import static cn.webank.eventmesh.common.protocol.tcp.Command.CLIENT_GOODBYE_RESPONSE; + +public class GoodbyeTask extends AbstractTask { + + public GoodbyeTask(Package pkg, ChannelHandlerContext ctx, long startTime, ProxyTCPServer proxyTCPServer) { + super(pkg, ctx, startTime, proxyTCPServer); + } + + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + Package msg = new Package(); + try { + if (pkg.getHeader().getCommand() == Command.SERVER_GOODBYE_RESPONSE) { + logger.info("client|address={}| has reject ", session.getContext().channel().remoteAddress()); + } else { + msg.setHeader(new Header(CLIENT_GOODBYE_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq + ())); + } + } catch (Exception e) { + logger.error("GoodbyeTask failed|user={}|errMsg={}", session.getClient(), e); + msg.setHeader(new Header(CLIENT_GOODBYE_RESPONSE, OPStatus.FAIL.getCode(), e.getStackTrace().toString(), pkg + .getHeader().getSeq())); + } finally { + ProxyTCPServer.scheduler.submit(new Runnable() { + @Override + public void run() { + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + } + }); + //session.write2Client(msg); + } + closeSessionIfTimeout(session, proxyTCPServer.getClientSessionGroupMapping()); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/HeartBeatTask.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/HeartBeatTask.java new file mode 100644 index 0000000000..0b09c5cd3e --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/HeartBeatTask.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/HeartBeatTask.java +package cn.webank.emesher.core.protocol.tcp.client.task; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.emesher.util.Utils; +======== +package com.webank.runtime.core.protocol.tcp.client.task; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.runtime.util.Utils; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/task/HeartBeatTask.java +import io.netty.channel.ChannelHandlerContext; + +import static cn.webank.eventmesh.common.protocol.tcp.Command.HEARTBEAT_RESPONSE; + +public class HeartBeatTask extends AbstractTask { + + public HeartBeatTask(Package pkg, ChannelHandlerContext ctx, long startTime, ProxyTCPServer proxyTCPServer) { + super(pkg, ctx, startTime, proxyTCPServer); + } + + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + Package res = new Package(); + try { + if (session != null) { + session.notifyHeartbeat(startTime); + } + res.setHeader(new Header(HEARTBEAT_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq())); + }catch (Exception e){ + logger.error("HeartBeatTask failed|user={}|errMsg={}", session.getClient(), e); + res.setHeader(new Header(HEARTBEAT_RESPONSE, OPStatus.FAIL.getCode(), "exception while " + + "heartbeating", pkg.getHeader().getSeq())); + }finally { + Utils.writeAndFlush(res, startTime, taskExecuteTime, session.getContext(), session); + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/HelloTask.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/HelloTask.java new file mode 100644 index 0000000000..6bc39444be --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/HelloTask.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/HelloTask.java +package cn.webank.emesher.core.protocol.tcp.client.task; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.common.ServiceState; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import cn.webank.emesher.util.Utils; +======== +package com.webank.runtime.core.protocol.tcp.client.task; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.common.ServiceState; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +import com.webank.runtime.util.Utils; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/task/HelloTask.java +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static cn.webank.eventmesh.common.protocol.tcp.Command.HELLO_RESPONSE; + +public class HelloTask extends AbstractTask { + + private final Logger messageLogger = LoggerFactory.getLogger("message"); + + public HelloTask(Package pkg, ChannelHandlerContext ctx, long startTime, ProxyTCPServer proxyTCPServer) { + super(pkg, ctx, startTime, proxyTCPServer); + } + + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + Package res = new Package(); + Session session = null; + UserAgent user = (UserAgent) pkg.getBody(); + try { + if(proxyTCPServer.getProxyServer().getServiceState() != ServiceState.RUNNING){ + logger.error("server state is not running:{}", proxyTCPServer.getProxyServer().getServiceState()); + throw new Exception("server state is not running, maybe deploying..."); + } + + validateUserAgent(user); + session = proxyTCPServer.getClientSessionGroupMapping().createSession(user, ctx); + res.setHeader(new Header(HELLO_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq())); + Utils.writeAndFlush(res, startTime, taskExecuteTime, session.getContext(), session); + } catch (Throwable e) { + messageLogger.error("HelloTask failed|address={},errMsg={}", ctx.channel().remoteAddress(), e); + res.setHeader(new Header(HELLO_RESPONSE, OPStatus.FAIL.getCode(), e.getStackTrace().toString(), pkg + .getHeader().getSeq())); + ctx.writeAndFlush(res).addListener( + new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (!future.isSuccess()) { + Utils.logFailedMessageFlow(future, res, user, startTime, taskExecuteTime); + } else { + Utils.logSucceedMessageFlow(res, user, startTime, taskExecuteTime); + } + logger.warn("HelloTask failed,close session,addr:{}", ctx.channel().remoteAddress()); + proxyTCPServer.getClientSessionGroupMapping().closeSession(ctx); + } + } + ); + } + } + + private void validateUserAgent(UserAgent user) throws Exception { + if (user == null) { + throw new Exception("client info cannot be null"); + } + + if (user.getVersion() == null) { + throw new Exception("client version cannot be null"); + } + +// if (user.getUsername() == null) { +// throw new Exception("client EventMeshUser cannot be null"); +// } +// +// if (user.getPassword() == null) { +// throw new Exception("client EventMeshPasswd cannot be null"); +// } + + if (!(StringUtils.equals(ProxyConstants.PURPOSE_PUB, user.getPurpose()) || StringUtils.equals(ProxyConstants.PURPOSE_SUB, user.getPurpose()))) { + throw new Exception("client purpose config is error"); + } + + if (StringUtils.equals(EventMeshConstants.PURPOSE_PUB, user.getPurpose()) + && StringUtils.isBlank(user.getProducerGroup())) { + throw new Exception("client producerGroup cannot be null"); + } + + if (StringUtils.equals(EventMeshConstants.PURPOSE_SUB, user.getPurpose()) + && StringUtils.isBlank(user.getConsumerGroup())) { + throw new Exception("client consumerGroup cannot be null"); + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/ListenTask.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/ListenTask.java new file mode 100644 index 0000000000..15f4982c58 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/ListenTask.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/ListenTask.java +package cn.webank.emesher.core.protocol.tcp.client.task; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +======== +package com.webank.runtime.core.protocol.tcp.client.task; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/task/ListenTask.java +import io.netty.channel.ChannelHandlerContext; + +import static cn.webank.eventmesh.common.protocol.tcp.Command.LISTEN_RESPONSE; + +public class ListenTask extends AbstractTask { + + public ListenTask(Package pkg, ChannelHandlerContext ctx, long startTime, ProxyTCPServer proxyTCPServer) { + super(pkg, ctx, startTime, proxyTCPServer); + } + + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + Header header = new Header(LISTEN_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq()); + session.setListenRequestSeq(pkg.getHeader().getSeq()); + try { + synchronized (session) { + proxyTCPServer.getClientSessionGroupMapping().readySession(session); + } + } catch (Exception e) { + logger.error("ListenTask failed|user={}|errMsg={}", session.getClient(), e); + Integer status = OPStatus.FAIL.getCode(); + header = new Header(LISTEN_RESPONSE, status, e.toString(), pkg.getHeader().getSeq()); + }finally { +// res.setHeader(header); +// writeAndFlush(res, startTime, session.getContext(), session); + //session.write2Client(res); + + //check to avoid send repeatedly + session.trySendListenResponse(header, startTime, taskExecuteTime); + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/MessageAckTask.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/MessageAckTask.java new file mode 100644 index 0000000000..b8db0b8e31 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/MessageAckTask.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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/MessageAckTask.java +package cn.webank.emesher.core.protocol.tcp.client.task; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.core.protocol.tcp.client.session.push.ClientAckContext; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +======== +package com.webank.runtime.core.protocol.tcp.client.task; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.core.protocol.tcp.client.session.push.ClientAckContext; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.Package; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/task/MessageAckTask.java +import io.netty.channel.ChannelHandlerContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageAckTask extends AbstractTask { + + private final Logger messageLogger = LoggerFactory.getLogger("message"); + + public MessageAckTask(Package pkg, ChannelHandlerContext ctx, long startTime, ProxyTCPServer proxyTCPServer) { + super(pkg, ctx, startTime, proxyTCPServer); + } + + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + String seq = pkg.getHeader().getSeq(); + Command cmd = pkg.getHeader().getCommand(); + + if (seq == null) { + logger.error("MessageAckTask failed, seq cannot be null|user={}", session.getClient()); + return; + } + ClientAckContext clientAckContext = session.getPusher().getPushContext().getUnAckMsg().get(seq); + if(clientAckContext != null) { + session.ackMsg(seq); + session.getClientGroupWrapper().get().getDownstreamMap().remove(seq); + } + messageLogger.info("pkg|c2proxy|cmd={}|seq=[{}]|user={}|wait={}ms|cost={}ms", cmd, seq, session.getClient(), + taskExecuteTime - startTime, System.currentTimeMillis() - startTime); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/MessageTransferTask.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/MessageTransferTask.java new file mode 100644 index 0000000000..4fa7ec6997 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/MessageTransferTask.java @@ -0,0 +1,182 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/MessageTransferTask.java +package cn.webank.emesher.core.protocol.tcp.client.task; + +import cn.webank.defibus.common.DeFiBusConstant; +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.session.send.ProxyTcpSendResult; +import cn.webank.emesher.core.protocol.tcp.client.session.send.ProxyTcpSendStatus; +import cn.webank.eventmesh.common.protocol.tcp.AccessMessage; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.emesher.util.ProxyUtil; +import cn.webank.emesher.util.Utils; +======== +package com.webank.runtime.core.protocol.tcp.client.task; + +import com.webank.defibus.common.DeFiBusConstant; +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.tcp.client.session.send.ProxyTcpSendResult; +import com.webank.runtime.core.protocol.tcp.client.session.send.ProxyTcpSendStatus; +import com.webank.eventmesh.common.protocol.tcp.AccessMessage; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.runtime.util.ProxyUtil; +import com.webank.runtime.util.Utils; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/task/MessageTransferTask.java +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.TimeUnit; + +import static cn.webank.eventmesh.common.protocol.tcp.Command.RESPONSE_TO_SERVER; + +public class MessageTransferTask extends AbstractTask { + + private final Logger messageLogger = LoggerFactory.getLogger("message"); + + private final int TRY_PERMIT_TIME_OUT = 5; + + public MessageTransferTask(Package pkg, ChannelHandlerContext ctx, long startTime, ProxyTCPServer proxyTCPServer) { + super(pkg, ctx, startTime, proxyTCPServer); + } + + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + Command cmd = pkg.getHeader().getCommand(); + Command replyCmd = getReplyCmd(cmd); + Package msg = new Package(); + AccessMessage accessMessage = (AccessMessage) pkg.getBody(); + int retCode = 0; + ProxyTcpSendResult sendStatus; + try { + if (accessMessage == null) { + throw new Exception("accessMessage is null"); + } + + if (!cmd.equals(RESPONSE_TO_SERVER) && !proxyTCPServer.rateLimiter.tryAcquire(TRY_PERMIT_TIME_OUT, TimeUnit.MILLISECONDS)) { + msg.setHeader(new Header(replyCmd, OPStatus.FAIL.getCode(), "Tps overload, global flow control", pkg.getHeader().getSeq())); + ctx.writeAndFlush(msg).addListener( + new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + Utils.logSucceedMessageFlow(msg, session.getClient(), startTime, taskExecuteTime); + } + } + ); + logger.warn("======Tps overload, global flow control, rate:{}! PLEASE CHECK!========", proxyTCPServer.rateLimiter.getRate()); + return; + } + + synchronized (session) { + long sendTime = System.currentTimeMillis(); + addTimestamp(accessMessage, cmd, sendTime); + if (cmd.equals(Command.REQUEST_TO_SERVER)) { + accessMessage.getProperties().put(DeFiBusConstant.PROPERTY_MESSAGE_REPLY_TO, session.getClientGroupWrapper() + .get().getDefibusProducer().getDefaultMQProducer().buildMQClientId()); + } + + sendStatus = session.upstreamMsg(pkg.getHeader(), ProxyUtil.decodeMessage(accessMessage), createSendCallback(replyCmd, taskExecuteTime, accessMessage), startTime, taskExecuteTime); + + if (StringUtils.equals(ProxyTcpSendStatus.SUCCESS.name(), sendStatus.getSendStatus().name())) { + messageLogger.info("pkg|proxy2mq|cmd={}|Msg={}|user={}|wait={}ms|cost={}ms", cmd, ProxyUtil.printMqMessage + (accessMessage), session.getClient(), taskExecuteTime - startTime, sendTime - startTime); + } else { + throw new Exception(sendStatus.getDetail()); + } + } + } catch (Exception e) { + logger.error("MessageTransferTask failed|cmd={}|Msg={}|user={}|errMsg={}", cmd, accessMessage, session.getClient(), e); + if (!cmd.equals(RESPONSE_TO_SERVER)) { + msg.setHeader(new Header(replyCmd, OPStatus.FAIL.getCode(), e.getStackTrace().toString(), pkg.getHeader() + .getSeq())); + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + } + } + } + + private void addTimestamp(AccessMessage accessMessage, Command cmd, long sendTime) { + if (cmd.equals(RESPONSE_TO_SERVER)) { + accessMessage.getProperties().put(ProxyConstants.RSP_C2PROXY_TIMESTAMP, String.valueOf(startTime)); + accessMessage.getProperties().put(ProxyConstants.RSP_PROXY2MQ_TIMESTAMP, String.valueOf(sendTime)); + accessMessage.getProperties().put(ProxyConstants.RSP_SEND_PROXY_IP, ProxyUtil.getLocalAddr()); + } else { + accessMessage.getProperties().put(ProxyConstants.REQ_C2PROXY_TIMESTAMP, String.valueOf(startTime)); + accessMessage.getProperties().put(ProxyConstants.REQ_PROXY2MQ_TIMESTAMP, String.valueOf(sendTime)); + accessMessage.getProperties().put(ProxyConstants.REQ_SEND_PROXY_IP, ProxyUtil.getLocalAddr()); + } + } + + private Command getReplyCmd(Command cmd) { + switch (cmd) { + case REQUEST_TO_SERVER: + return Command.RESPONSE_TO_CLIENT; + case ASYNC_MESSAGE_TO_SERVER: + return Command.ASYNC_MESSAGE_TO_SERVER_ACK; + case BROADCAST_MESSAGE_TO_SERVER: + return Command.BROADCAST_MESSAGE_TO_SERVER_ACK; + default: + return cmd; + } + } + + protected SendCallback createSendCallback(Command replyCmd, long taskExecuteTime, AccessMessage accessMessage) { + final long createTime = System.currentTimeMillis(); + Package msg = new Package(); + + return new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + session.getSender().getUpstreamBuff().release(); + messageLogger.info("upstreamMsg message success|user={}|callback cost={}", session.getClient(), + String.valueOf(System.currentTimeMillis() - createTime)); + if (replyCmd.equals(Command.BROADCAST_MESSAGE_TO_SERVER_ACK) || replyCmd.equals(Command + .ASYNC_MESSAGE_TO_SERVER_ACK)) { + msg.setHeader(new Header(replyCmd, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq())); + msg.setBody(accessMessage); + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + } + } + + @Override + public void onException(Throwable e) { + session.getSender().getUpstreamBuff().release(); + session.getSender().failMsgCount.incrementAndGet(); + messageLogger.error("upstreamMsg mq message error|user={}|callback cost={}, errMsg={}", session.getClient(), String.valueOf + (System.currentTimeMillis() - createTime), new Exception(e)); + msg.setHeader(new Header(replyCmd, OPStatus.FAIL.getCode(), e.toString(), pkg.getHeader().getSeq())); + msg.setBody(accessMessage); + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + } + }; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/SubscribeTask.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/SubscribeTask.java new file mode 100644 index 0000000000..5515d8b8ec --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/SubscribeTask.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/SubscribeTask.java +package cn.webank.emesher.core.protocol.tcp.client.task; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.Subscription; +import cn.webank.emesher.util.ProxyUtil; +import cn.webank.emesher.util.Utils; +======== +package com.webank.runtime.core.protocol.tcp.client.task; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.eventmesh.common.protocol.tcp.Subscription; +import com.webank.runtime.util.ProxyUtil; +import com.webank.runtime.util.Utils; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/task/SubscribeTask.java +import io.netty.channel.ChannelHandlerContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class SubscribeTask extends AbstractTask { + + private final Logger messageLogger = LoggerFactory.getLogger("message"); + + public SubscribeTask(Package pkg, ChannelHandlerContext ctx, long startTime, ProxyTCPServer proxyTCPServer) { + super(pkg, ctx, startTime, proxyTCPServer); + } + + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + Package msg = new Package(); + try { + Subscription subscriptionInfo = (Subscription) pkg.getBody(); + if (subscriptionInfo == null) { + throw new Exception("subscriptionInfo is null"); + } + + List topicList = new ArrayList<>(); + for (int i = 0; i < subscriptionInfo.getTopicList().size(); i++) { + String topic = subscriptionInfo.getTopicList().get(i); + if (!ProxyUtil.isValidRMBTopic(topic)) { + throw new Exception("invalid topic!"); + } + topicList.add(topic); + } + synchronized (session) { + session.subscribe(topicList); + messageLogger.info("SubscribeTask succeed|user={}|topics={}", session.getClient(), topicList); + } + msg.setHeader(new Header(Command.SUBSCRIBE_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader() + .getSeq())); + } catch (Exception e) { + messageLogger.error("SubscribeTask failed|user={}|errMsg={}", session.getClient(), e); + msg.setHeader(new Header(Command.SUBSCRIBE_RESPONSE, OPStatus.FAIL.getCode(), e.toString(), pkg.getHeader() + .getSeq())); + } finally { + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + } + } + + +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/UnSubscribeTask.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/UnSubscribeTask.java new file mode 100644 index 0000000000..24a25b314d --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/UnSubscribeTask.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/core/protocol/tcp/client/task/UnSubscribeTask.java +package cn.webank.emesher.core.protocol.tcp.client.task; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.OPStatus; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.emesher.util.Utils; +======== +package com.webank.runtime.core.protocol.tcp.client.task; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.OPStatus; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.runtime.util.Utils; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/core/protocol/tcp/client/task/UnSubscribeTask.java +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.collections4.MapUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class UnSubscribeTask extends AbstractTask { + + private final Logger messageLogger = LoggerFactory.getLogger("message"); + + public UnSubscribeTask(Package pkg, ChannelHandlerContext ctx, long startTime, ProxyTCPServer proxyTCPServer) { + super(pkg, ctx, startTime, proxyTCPServer); + } + + @Override + public void run() { + long taskExecuteTime = System.currentTimeMillis(); + Package msg = new Package(); + try { + synchronized (session) { + List topics = new ArrayList(); + if (MapUtils.isNotEmpty(session.getSessionContext().subscribeTopics)) { + for (String topic : session.getSessionContext().subscribeTopics.keySet()) { + topics.add(topic); + } + session.unsubscribe(topics); + messageLogger.info("UnSubscriberTask succeed|user={}|topics={}", session.getClient(), topics); + } + } + msg.setHeader(new Header(Command.UNSUBSCRIBE_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader() + .getSeq())); + } catch (Exception e) { + messageLogger.error("UnSubscribeTask failed|user={}|errMsg={}", session.getClient(), e); + msg.setHeader(new Header(Command.UNSUBSCRIBE_RESPONSE, OPStatus.FAIL.getCode(), "exception while " + + "unSubscribing", pkg.getHeader().getSeq())); + } finally { + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + } + } + + +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/MonitorMetricConstants.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/MonitorMetricConstants.java new file mode 100644 index 0000000000..5ba418d876 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/MonitorMetricConstants.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/MonitorMetricConstants.java +package cn.webank.emesher.metrics; +======== +package com.webank.runtime.metrics; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/metrics/MonitorMetricConstants.java + +public class MonitorMetricConstants { + public static final String PROXY_MONITOR_FORMAT_COMMON = "{\"protocol\":\"%s\",\"s\":\"%s\",\"t\":\"%s\"}"; + + public static final String PROXY_TCP_MONITOR_FORMAT_THREADPOOL = "{\"threadPoolName\":\"%s\",\"s\":\"%s\",\"t\":\"%s\"}"; + + public static final String CLIENT_2_PROXY_TPS = "client2proxyTPS"; + public static final String PROXY_2_MQ_TPS = "proxy2mqTPS"; + public static final String MQ_2_PROXY_TPS = "mq2proxyTPS"; + public static final String PROXY_2_CLIENT_TPS = "proxy2clientTPS"; + public static final String ALL_TPS = "allTPS"; + public static final String CONNECTION = "connection"; + public static final String SUB_TOPIC_NUM = "subTopicNum"; + + public static final String RETRY_QUEUE_SIZE = "retryQueueSize"; + + + public static final String QUEUE_SIZE = "queueSize"; + public static final String POOL_SIZE = "poolSize"; + public static final String ACTIVE_COUNT = "activeCount"; + public static final String COMPLETED_TASK = "completedTask"; +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/GroupMetrics.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/GroupMetrics.java new file mode 100644 index 0000000000..838ff2a58b --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/GroupMetrics.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/GroupMetrics.java +package cn.webank.emesher.metrics.http; + +import cn.webank.emesher.boot.ProxyHTTPServer; +======== +package com.webank.runtime.metrics.http; + +import com.webank.runtime.boot.ProxyHTTPServer; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/metrics/http/GroupMetrics.java +import com.codahale.metrics.MetricRegistry; + +public class GroupMetrics { + + private ProxyHTTPServer proxyHTTPServer; + + private MetricRegistry metricRegistry; + + public GroupMetrics(ProxyHTTPServer proxyHTTPServer, MetricRegistry metricRegistry) { + this.proxyHTTPServer = proxyHTTPServer; + this.metricRegistry = metricRegistry; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/HTTPMetricsServer.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/HTTPMetricsServer.java new file mode 100644 index 0000000000..78d8f80079 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/HTTPMetricsServer.java @@ -0,0 +1,182 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/HTTPMetricsServer.java +package cn.webank.emesher.metrics.http; + +import cn.webank.emesher.boot.ProxyHTTPServer; +======== +package com.webank.runtime.metrics.http; + +import com.webank.runtime.boot.ProxyHTTPServer; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/metrics/http/HTTPMetricsServer.java +import com.codahale.metrics.MetricRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class HTTPMetricsServer { + + private ProxyHTTPServer proxyHTTPServer; + + private MetricRegistry metricRegistry = new MetricRegistry(); + + public SummaryMetrics summaryMetrics; + + public HealthMetrics healthMetrics; + + public TopicMetrics topicMetrics; + + public GroupMetrics groupMetrics; + + private Logger httpLogger = LoggerFactory.getLogger("httpMonitor"); + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + public HTTPMetricsServer(ProxyHTTPServer proxyHTTPServer) { + this.proxyHTTPServer = proxyHTTPServer; + } + + public void init() throws Exception { + summaryMetrics = new SummaryMetrics(this.proxyHTTPServer, this.metricRegistry); + topicMetrics = new TopicMetrics(this.proxyHTTPServer, this.metricRegistry); + groupMetrics = new GroupMetrics(this.proxyHTTPServer, this.metricRegistry); + healthMetrics = new HealthMetrics(this.proxyHTTPServer, this.metricRegistry); + logger.info("HTTPMetricsServer inited......"); + } + + public void start() throws Exception { + metricsSchedule.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + try { + summaryMetrics.snapshotHTTPTPS(); + summaryMetrics.snapshotSendBatchMsgTPS(); + summaryMetrics.snapshotSendMsgTPS(); + summaryMetrics.snapshotPushMsgTPS(); + } catch (Exception ex) { + logger.warn("proxy snapshot tps metrics err", ex); + } + } + }, 0, 1000, TimeUnit.MILLISECONDS); + + metricsSchedule.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + try { + logPrintServerMetrics(); + } catch (Exception ex) { + logger.warn("proxy print metrics err", ex); + } + } + }, 1000, SummaryMetrics.STATIC_PERIOD, TimeUnit.MILLISECONDS); + + logger.info("HTTPMetricsServer started......"); + } + + public void shutdown() throws Exception { + metricsSchedule.shutdown(); + logger.info("HTTPMetricsServer shutdown......"); + } + + protected static ScheduledExecutorService metricsSchedule = Executors.newScheduledThreadPool(2, new ThreadFactory() { + private AtomicInteger seq = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + seq.incrementAndGet(); + Thread t = new Thread(r, "proxy-metrics-" + seq.get()); + t.setDaemon(true); + return t; + } + }); + + private void logPrintServerMetrics() { + httpLogger.info("===========================================SERVER METRICS=================================================="); + + httpLogger.info(String.format(SummaryMetrics.PROXY_MONITOR_FORMAT_HTTP, + summaryMetrics.maxHTTPTPS(), + summaryMetrics.avgHTTPTPS(), + summaryMetrics.maxHTTPCost(), + summaryMetrics.avgHTTPCost(), + summaryMetrics.avgHTTPBodyDecodeCost(), + summaryMetrics.getHttpDiscard())); + summaryMetrics.httpStatInfoClear(); + + httpLogger.info(String.format(SummaryMetrics.PROXY_MONITOR_FORMAT_BATCHSENDMSG, + summaryMetrics.maxSendBatchMsgTPS(), + summaryMetrics.avgSendBatchMsgTPS(), + summaryMetrics.getSendBatchMsgNumSum(), + summaryMetrics.getSendBatchMsgFailNumSum(), + summaryMetrics.getSendBatchMsgFailRate(), + summaryMetrics.getSendBatchMsgDiscardNumSum() + )); + summaryMetrics.cleanSendBatchStat(); + + httpLogger.info(String.format(SummaryMetrics.PROXY_MONITOR_FORMAT_SENDMSG, + summaryMetrics.maxSendMsgTPS(), + summaryMetrics.avgSendMsgTPS(), + summaryMetrics.getSendMsgNumSum(), + summaryMetrics.getSendMsgFailNumSum(), + summaryMetrics.getSendMsgFailRate(), + summaryMetrics.getReplyMsgNumSum(), + summaryMetrics.getReplyMsgFailNumSum() + )); + summaryMetrics.cleanSendMsgStat(); + + httpLogger.info(String.format(SummaryMetrics.PROXY_MONITOR_FORMAT_PUSHMSG, + summaryMetrics.maxPushMsgTPS(), + summaryMetrics.avgPushMsgTPS(), + summaryMetrics.getHttpPushMsgNumSum(), + summaryMetrics.getHttpPushFailNumSum(), + summaryMetrics.getHttpPushMsgFailRate(), + summaryMetrics.maxHTTPPushLatency(), + summaryMetrics.avgHTTPPushLatency() + )); + summaryMetrics.cleanHttpPushMsgStat(); + + httpLogger.info(String.format(SummaryMetrics.PROXY_MONITOR_FORMAT_BLOCKQ, + proxyHTTPServer.getBatchMsgExecutor().getQueue().size(), + proxyHTTPServer.getSendMsgExecutor().getQueue().size(), + proxyHTTPServer.getPushMsgExecutor().getQueue().size(), + proxyHTTPServer.getHttpRetryer().size())); + + httpLogger.info(String.format(SummaryMetrics.PROXY_MONITOR_FORMAT_MQ_CLIENT, + summaryMetrics.avgBatchSendMsgCost(), + summaryMetrics.avgSendMsgCost(), + summaryMetrics.avgReplyMsgCost())); + summaryMetrics.send2MQStatInfoClear(); + } + + + public HealthMetrics getHealthMetrics() { + return healthMetrics; + } + + public TopicMetrics getTopicMetrics() { + return topicMetrics; + } + + public GroupMetrics getGroupMetrics() { + return groupMetrics; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/HealthMetrics.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/HealthMetrics.java new file mode 100644 index 0000000000..263805fd73 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/HealthMetrics.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/HealthMetrics.java +package cn.webank.emesher.metrics.http; + +import cn.webank.emesher.boot.ProxyHTTPServer; +======== +package com.webank.runtime.metrics.http; + +import com.webank.runtime.boot.ProxyHTTPServer; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/metrics/http/HealthMetrics.java +import com.codahale.metrics.MetricRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HealthMetrics { + + private ProxyHTTPServer proxyHTTPServer; + private MetricRegistry metricRegistry; + + public Logger logger = LoggerFactory.getLogger("httpMonitor"); + + public HealthMetrics(ProxyHTTPServer proxyHTTPServer, MetricRegistry metricRegistry) { + this.proxyHTTPServer = proxyHTTPServer; + this.metricRegistry = metricRegistry; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/SummaryMetrics.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/SummaryMetrics.java new file mode 100644 index 0000000000..3230aa238d --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/SummaryMetrics.java @@ -0,0 +1,441 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/SummaryMetrics.java +package cn.webank.emesher.metrics.http; + +import cn.webank.emesher.boot.ProxyHTTPServer; +======== +package com.webank.runtime.metrics.http; + +import com.webank.runtime.boot.ProxyHTTPServer; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/metrics/http/SummaryMetrics.java +import com.codahale.metrics.MetricRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicLong; + +public class SummaryMetrics { + + public Logger logger = LoggerFactory.getLogger("httpMonitor"); + + private ProxyHTTPServer proxyHTTPServer; + + private MetricRegistry metricRegistry; + + public SummaryMetrics(ProxyHTTPServer proxyHTTPServer, MetricRegistry metricRegistry) { + this.proxyHTTPServer = proxyHTTPServer; + this.metricRegistry = metricRegistry; + } + + public static final int STATIC_PERIOD = 30 * 1000; + + private float avg(LinkedList linkedList) { + float sum = 0.0f; + if (linkedList.isEmpty()) { + return sum; + } + + Iterator it = linkedList.iterator(); + while (it.hasNext()) { + float tps = (float) it.next(); + sum += tps; + } + + return sum / linkedList.size(); + } + + //////////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_HTTP = "{\"maxHTTPTPS\":\"%.1f\",\"avgHTTPTPS\":\"%.1f\"," + //PROXY 接受外部HTTP 请求的TPS相关 + "\"maxHTTPCOST\":\"%s\",\"avgHTTPCOST\":\"%.1f\",\"avgHTTPBodyDecodeCost\":\"%.1f\", \"httpDiscard\":\"%s\"}"; + + private float wholeCost = 0f; + + private AtomicLong wholeRequestNum = new AtomicLong(0); + + //累计值 + private AtomicLong httpDiscard = new AtomicLong(0); + + private AtomicLong maxCost = new AtomicLong(0); + + private AtomicLong httpRequestPerSecond = new AtomicLong(0); + + private LinkedList httpRequestTPSSnapshots = new LinkedList(); + + public float avgHTTPCost() { + float cost = (wholeRequestNum.longValue() == 0l) ? 0f : wholeCost / wholeRequestNum.longValue(); + return cost; + } + + public long maxHTTPCost() { + long cost = maxCost.longValue(); + return cost; + } + + public long getHttpDiscard() { + return httpDiscard.longValue(); + } + + public void recordHTTPRequest() { + httpRequestPerSecond.incrementAndGet(); + } + + public void recordHTTPDiscard() { + httpDiscard.incrementAndGet(); + } + + public void snapshotHTTPTPS() { + Integer tps = httpRequestPerSecond.intValue(); + httpRequestTPSSnapshots.add(tps); + httpRequestPerSecond.set(0); + if (httpRequestTPSSnapshots.size() > STATIC_PERIOD / 1000) { + httpRequestTPSSnapshots.removeFirst(); + } + } + + public float maxHTTPTPS() { + float tps = Collections.max(httpRequestTPSSnapshots); + return tps; + } + + public float avgHTTPTPS() { + float tps = avg(httpRequestTPSSnapshots); + return tps; + } + + public void recordHTTPReqResTimeCost(long cost) { + wholeRequestNum.incrementAndGet(); + wholeCost = wholeCost + cost; + if (cost > maxCost.longValue()) { + maxCost.set(cost); + } + } + + public void httpStatInfoClear() { + wholeRequestNum.set(0l); + wholeCost = 0f; + maxCost.set(0l); + httpDecodeNum.set(0l); + httpDecodeTimeCost = 0f; + } + + private float httpDecodeTimeCost = 0f; + + private AtomicLong httpDecodeNum = new AtomicLong(0); + + public void recordDecodeTimeCost(long cost) { + httpDecodeNum.incrementAndGet(); + httpDecodeTimeCost = httpDecodeTimeCost + cost; + } + + public float avgHTTPBodyDecodeCost() { + float cost = (httpDecodeNum.longValue() == 0l) ? 0f : httpDecodeTimeCost / httpDecodeNum.longValue(); + return cost; + } + + + ////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_BATCHSENDMSG = "{\"maxBatchSendMsgTPS\":\"%.1f\",\"avgBatchSendMsgTPS\":\"%.1f\"," + + " \"sum\":\"%s\", \"sumFail\":\"%s\", \"sumFailRate\":\"%.2f\", \"discard\":\"%s\"}"; + + private AtomicLong sendBatchMsgNumPerSecond = new AtomicLong(0); + + private AtomicLong sendBatchMsgNumSum = new AtomicLong(0); + + private AtomicLong sendBatchMsgFailNumSum = new AtomicLong(0); + + // This is a cumulative value + private AtomicLong sendBatchMsgDiscardNumSum = new AtomicLong(0); + + public void recordSendBatchMsgDiscard(long delta) { + sendBatchMsgDiscardNumSum.addAndGet(delta); + } + + private LinkedList sendBatchMsgTPSSnapshots = new LinkedList(); + + public void snapshotSendBatchMsgTPS() { + Integer tps = sendBatchMsgNumPerSecond.intValue(); + sendBatchMsgTPSSnapshots.add(tps); + sendBatchMsgNumPerSecond.set(0); + if (sendBatchMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { + sendBatchMsgTPSSnapshots.removeFirst(); + } + } + + public float maxSendBatchMsgTPS() { + float tps = Collections.max(sendBatchMsgTPSSnapshots); + return tps; + } + + public float avgSendBatchMsgTPS() { + float tps = avg(sendBatchMsgTPSSnapshots); + return tps; + } + + public void recordSendBatchMsg(long delta) { + sendBatchMsgNumPerSecond.addAndGet(delta); + sendBatchMsgNumSum.addAndGet(delta); + } + + public void recordSendBatchMsgFailed(long delta) { + sendBatchMsgFailNumSum.getAndAdd(delta); + } + + public long getSendBatchMsgNumSum() { + return sendBatchMsgNumSum.longValue(); + } + + public long getSendBatchMsgFailNumSum() { + return sendBatchMsgFailNumSum.longValue(); + } + + public float getSendBatchMsgFailRate() { + return (sendBatchMsgNumSum.longValue() == 0l) ? 0f : sendBatchMsgFailNumSum.floatValue() / sendBatchMsgNumSum.longValue(); + } + + public void cleanSendBatchStat() { + sendBatchMsgNumSum.set(0l); + sendBatchMsgFailNumSum.set(0l); + } + + public long getSendBatchMsgDiscardNumSum() { + return sendBatchMsgDiscardNumSum.longValue(); + } + + ////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_SENDMSG = "{\"maxSendMsgTPS\":\"%.1f\",\"avgSendMsgTPS\":\"%.1f\"," + + " \"sum\":\"%s\", \"sumFail\":\"%s\", \"sumFailRate\":\"%.2f\", \"replyMsg\":\"%s\", \"replyFail\":\"%s\"}"; + + private AtomicLong sendMsgNumSum = new AtomicLong(0); + + private AtomicLong sendMsgFailNumSum = new AtomicLong(0); + + private AtomicLong replyMsgNumSum = new AtomicLong(0); + + private AtomicLong replyMsgFailNumSum = new AtomicLong(0); + + private AtomicLong sendMsgNumPerSecond = new AtomicLong(0); + + private LinkedList sendMsgTPSSnapshots = new LinkedList(); + + public void snapshotSendMsgTPS() { + Integer tps = sendMsgNumPerSecond.intValue(); + sendMsgTPSSnapshots.add(tps); + sendMsgNumPerSecond.set(0); + if (sendMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { + sendMsgTPSSnapshots.removeFirst(); + } + } + + public float maxSendMsgTPS() { + float tps = Collections.max(sendMsgTPSSnapshots); + return tps; + } + + public float avgSendMsgTPS() { + float tps = avg(sendMsgTPSSnapshots); + return tps; + } + + public void recordSendMsg() { + sendMsgNumPerSecond.incrementAndGet(); + sendMsgNumSum.incrementAndGet(); + } + + public void recordReplyMsg() { + replyMsgNumSum.incrementAndGet(); + } + + public void recordReplyMsgFailed() { + replyMsgFailNumSum.incrementAndGet(); + } + + public long getReplyMsgNumSum() { + return replyMsgNumSum.longValue(); + } + + public long getReplyMsgFailNumSum() { + return replyMsgFailNumSum.longValue(); + } + + public long getSendMsgNumSum() { + return sendMsgNumSum.longValue(); + } + + public long getSendMsgFailNumSum() { + return sendMsgFailNumSum.longValue(); + } + + public float getSendMsgFailRate() { + return (sendMsgNumSum.longValue() == 0l) ? 0f : sendMsgFailNumSum.floatValue() / sendMsgNumSum.longValue(); + } + + public void recordSendMsgFailed() { + sendMsgFailNumSum.incrementAndGet(); + } + + public void cleanSendMsgStat() { + sendMsgNumSum.set(0l); + replyMsgNumSum.set(0l); + sendMsgFailNumSum.set(0l); + replyMsgFailNumSum.set(0l); + } + + //////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_PUSHMSG = "{\"maxPushMsgTPS\":\"%.1f\",\"avgPushMsgTPS\":\"%.1f\"," + + " \"sum\":\"%s\", \"sumFail\":\"%s\", \"sumFailRate\":\"%.1f\", \"maxClientLatency\":\"%.1f\", \"avgClientLatency\":\"%.1f\"}"; + + private float wholePushCost = 0f; + + private AtomicLong wholePushRequestNum = new AtomicLong(0); + + private AtomicLong maxHttpPushLatency = new AtomicLong(0); + + private AtomicLong pushMsgNumPerSecond = new AtomicLong(0); + + private LinkedList pushMsgTPSSnapshots = new LinkedList(); + + private AtomicLong httpPushMsgNumSum = new AtomicLong(0); + + private AtomicLong httpPushFailNumSum = new AtomicLong(0); + + public void snapshotPushMsgTPS() { + Integer tps = pushMsgNumPerSecond.intValue(); + pushMsgTPSSnapshots.add(tps); + pushMsgNumPerSecond.set(0); + if (pushMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { + pushMsgTPSSnapshots.removeFirst(); + } + } + + public void recordHTTPPushTimeCost(long cost) { + wholePushRequestNum.incrementAndGet(); + wholePushCost = wholePushCost + cost; + if (cost > maxHttpPushLatency.longValue()) { + maxHttpPushLatency.set(cost); + } + } + + public float avgHTTPPushLatency() { + return (wholePushRequestNum.longValue() == 0l) ? 0f : wholePushCost / wholePushRequestNum.longValue(); + } + + public float maxHTTPPushLatency() { + return maxHttpPushLatency.floatValue(); + } + + public float maxPushMsgTPS() { + float tps = Collections.max(pushMsgTPSSnapshots); + return tps; + } + + public float avgPushMsgTPS() { + float tps = avg(pushMsgTPSSnapshots); + return tps; + } + + public void recordPushMsg() { + pushMsgNumPerSecond.incrementAndGet(); + httpPushMsgNumSum.incrementAndGet(); + } + + public long getHttpPushMsgNumSum() { + return httpPushMsgNumSum.longValue(); + } + + public long getHttpPushFailNumSum() { + return httpPushFailNumSum.longValue(); + } + + public float getHttpPushMsgFailRate() { + return (httpPushMsgNumSum.longValue() == 0l) ? 0f : httpPushFailNumSum.floatValue() / httpPushMsgNumSum.longValue(); + } + + public void recordHttpPushMsgFailed() { + sendMsgFailNumSum.incrementAndGet(); + } + + public void cleanHttpPushMsgStat() { + httpPushFailNumSum.set(0l); + httpPushMsgNumSum.set(0l); + wholeRequestNum.set(0l); + wholeCost = 0f; + maxCost.set(0l); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_BLOCKQ = "{\"batchMsgQ\":\"%s\",\"sendMsgQ\":\"%s\"," + + "\"pushMsgQ\":\"%s\",\"httpRetryQ\":\"%s\"}"; + + /////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_MQ_CLIENT = "{\"batchAvgSend2MQCost\":\"%.1f\", \"avgSend2MQCost\":\"%.1f\", \"avgReply2MQCost\":\"%.1f\"}"; + + private float batchSend2MQWholeCost = 0f; + + private AtomicLong batchSend2MQNum = new AtomicLong(0); + + private float send2MQWholeCost = 0f; + + private AtomicLong send2MQNum = new AtomicLong(0); + + private float reply2MQWholeCost = 0f; + + private AtomicLong reply2MQNum = new AtomicLong(0); + + public void recordBatchSendMsgCost(long cost) { + batchSend2MQNum.incrementAndGet(); + batchSend2MQWholeCost = batchSend2MQWholeCost + cost; + } + + public float avgBatchSendMsgCost() { + float cost = (batchSend2MQNum.intValue() == 0) ? 0f : batchSend2MQWholeCost / batchSend2MQNum.intValue(); + return cost; + } + + public void recordSendMsgCost(long cost) { + send2MQNum.incrementAndGet(); + send2MQWholeCost = send2MQWholeCost + cost; + } + + public float avgSendMsgCost() { + float cost = (send2MQNum.intValue() == 0) ? 0f : send2MQWholeCost / send2MQNum.intValue(); + return cost; + } + + public void recordReplyMsgCost(long cost) { + reply2MQNum.incrementAndGet(); + reply2MQWholeCost = reply2MQWholeCost + cost; + } + + public float avgReplyMsgCost() { + float cost = (reply2MQNum.intValue() == 0) ? 0f : reply2MQWholeCost / reply2MQNum.intValue(); + return cost; + } + + public void send2MQStatInfoClear() { + batchSend2MQWholeCost = 0f; + batchSend2MQNum.set(0l); + send2MQWholeCost = 0f; + send2MQNum.set(0l); + reply2MQWholeCost = 0f; + reply2MQNum.set(0l); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/TcpSummaryMetrics.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/TcpSummaryMetrics.java new file mode 100644 index 0000000000..858e968be7 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/TcpSummaryMetrics.java @@ -0,0 +1,400 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/TcpSummaryMetrics.java +package cn.webank.emesher.metrics.http; + +import cn.webank.emesher.boot.ProxyHTTPServer; +======== +package com.webank.runtime.metrics.http; + +import com.webank.runtime.boot.ProxyHTTPServer; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/metrics/http/TcpSummaryMetrics.java +import com.codahale.metrics.MetricRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicLong; + +public class TcpSummaryMetrics { + + public Logger logger = LoggerFactory.getLogger("httpMonitor"); + + private ProxyHTTPServer proxyHTTPServer; + private MetricRegistry metricRegistry; + + public TcpSummaryMetrics(ProxyHTTPServer proxyHTTPServer, MetricRegistry metricRegistry) { + this.proxyHTTPServer = proxyHTTPServer; + this.metricRegistry = metricRegistry; + } + + public static final int STATIC_PERIOD = 30 * 1000; + + private float avg(LinkedList linkedList) { + float sum = 0.0f; + if (linkedList.isEmpty()) { + return sum; + } + + Iterator it = linkedList.iterator(); + while (it.hasNext()) { + float tps = (float) it.next(); + sum += tps; + } + + return sum / linkedList.size(); + } + + //////////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_HTTP = "%15s : {\"maxHTTPTPS\":\"%.1f\",\"avgHTTPTPS\":\"%.1f\"," + //PROXY 接受外部HTTP 请求的TPS相关 + "\"maxHTTPCOST\":\"%s\",\"avgHTTPCOST\":\"%.1f\",\"avgHTTPBodyDecodeCost\":\"%.1f\"}"; + + private float wholeCost = 0f; + + private AtomicLong wholeRequestNum = new AtomicLong(0); + + private AtomicLong maxCost = new AtomicLong(0); + + private AtomicLong httpRequestPerSecond = new AtomicLong(0); + + private LinkedList httpRequestTPSSnapshots = new LinkedList(); + + public float avgHTTPCost() { + float cost = (wholeRequestNum.longValue() == 0l) ? 0f : wholeCost / wholeRequestNum.longValue(); + return cost; + } + + public long maxHTTPCost() { + long cost = maxCost.longValue(); + return cost; + } + + public void recordHTTPRequest() { + httpRequestPerSecond.incrementAndGet(); + } + + public void snapshotHTTPTPS() { + Integer tps = httpRequestPerSecond.intValue(); + httpRequestTPSSnapshots.add(tps); + httpRequestPerSecond.set(0); + if (httpRequestTPSSnapshots.size() > STATIC_PERIOD / 1000) { + httpRequestTPSSnapshots.removeFirst(); + } + } + + public float maxHTTPTPS() { + float tps = Collections.max(httpRequestTPSSnapshots); + return tps; + } + + public float avgHTTPTPS() { + float tps = avg(httpRequestTPSSnapshots); + return tps; + } + + public void recordHTTPReqResTimeCost(long cost) { + wholeRequestNum.incrementAndGet(); + wholeCost = wholeCost + cost; + if (cost > maxCost.longValue()) { + maxCost.set(cost); + } + } + + public void httpStatInfoClear() { + wholeRequestNum.set(0l); + wholeCost = 0f; + maxCost.set(0l); + httpDecodeNum.set(0l); + httpDecodeTimeCost = 0f; + } + + private float httpDecodeTimeCost = 0f; + + private AtomicLong httpDecodeNum = new AtomicLong(0); + + public void recordDecodeTimeCost(long cost) { + httpDecodeNum.incrementAndGet(); + httpDecodeTimeCost = httpDecodeTimeCost + cost; + } + + public float avgHTTPBodyDecodeCost() { + float cost = (httpDecodeNum.longValue() == 0l) ? 0f : httpDecodeTimeCost / httpDecodeNum.longValue(); + return cost; + } + + + ////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_BATCHSENDMSG = "%15s : {\"maxBatchSendMsgTPS\":\"%.1f\",\"avgBatchSendMsgTPS\":\"%.1f\"," + + " \"sum\":\"%s\", \"sumFail\":\"%s\", \"sumFailRate\":\"%.2f\", \"discard\":\"%s\"}"; + + private AtomicLong sendBatchMsgNumPerSecond = new AtomicLong(0); + + private AtomicLong sendBatchMsgNumSum = new AtomicLong(0); + + private AtomicLong sendBatchMsgFailNumSum = new AtomicLong(0); + + private AtomicLong sendBatchMsgDiscardNumSum = new AtomicLong(0); + + public void recordSendBatchMsgDiscard(long delta) { + sendBatchMsgDiscardNumSum.addAndGet(delta); + } + + private LinkedList sendBatchMsgTPSSnapshots = new LinkedList(); + + public void snapshotSendBatchMsgTPS() { + Integer tps = sendBatchMsgNumPerSecond.intValue(); + sendBatchMsgTPSSnapshots.add(tps); + sendBatchMsgNumPerSecond.set(0); + if (sendBatchMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { + sendBatchMsgTPSSnapshots.removeFirst(); + } + } + + public float maxSendBatchMsgTPS() { + float tps = Collections.max(sendBatchMsgTPSSnapshots); + return tps; + } + + public float avgSendBatchMsgTPS() { + float tps = avg(sendBatchMsgTPSSnapshots); + return tps; + } + + public void recordSendBatchMsg(long delta) { + sendBatchMsgNumPerSecond.addAndGet(delta); + sendBatchMsgNumSum.addAndGet(delta); + } + + public void recordSendBatchMsgFailed(long delta) { + sendBatchMsgFailNumSum.getAndAdd(delta); + } + + public long getSendBatchMsgNumSum() { + return sendBatchMsgNumSum.longValue(); + } + + public long getSendBatchMsgFailNumSum() { + return sendBatchMsgFailNumSum.longValue(); + } + + public float getSendBatchMsgFailRate() { + return (sendBatchMsgNumSum.longValue() == 0l) ? 0f : sendBatchMsgFailNumSum.floatValue() / sendBatchMsgNumSum.longValue(); + } + + public void cleanSendBatchStat() { + sendBatchMsgNumSum.set(0l); + sendBatchMsgFailNumSum.set(0l); + } + + public long getSendBatchMsgDiscardNumSum() { + return sendBatchMsgDiscardNumSum.longValue(); + } + + ////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_SENDMSG = "%15s : {\"maxSendMsgTPS\":\"%.1f\",\"avgSendMsgTPS\":\"%.1f\"," + + " \"sum\":\"%s\", \"sumFail\":\"%s\", \"sumFailRate\":\"%.2f\", \"discard\":\"%s\"}"; + + private AtomicLong sendMsgNumSum = new AtomicLong(0); + + private AtomicLong sendMsgFailNumSum = new AtomicLong(0); + + private AtomicLong sendMsgDiscardNumSum = new AtomicLong(0); + + private AtomicLong sendMsgNumPerSecond = new AtomicLong(0); + + private LinkedList sendMsgTPSSnapshots = new LinkedList(); + + public void snapshotSendMsgTPS() { + Integer tps = sendMsgNumPerSecond.intValue(); + sendMsgTPSSnapshots.add(tps); + sendMsgNumPerSecond.set(0); + if (sendMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { + sendMsgTPSSnapshots.removeFirst(); + } + } + + public float maxSendMsgTPS() { + float tps = Collections.max(sendMsgTPSSnapshots); + return tps; + } + + public float avgSendMsgTPS() { + float tps = avg(sendMsgTPSSnapshots); + return tps; + } + + public void recordSendMsg() { + sendMsgNumPerSecond.incrementAndGet(); + sendMsgNumSum.incrementAndGet(); + } + + public long getSendMsgNumSum() { + return sendMsgNumSum.longValue(); + } + + public long getSendMsgFailNumSum() { + return sendMsgFailNumSum.longValue(); + } + + public float getSendMsgFailRate() { + return (sendMsgNumSum.longValue() == 0l) ? 0f : sendMsgFailNumSum.floatValue() / sendMsgNumSum.longValue(); + } + + public void recordSendMsgFailed() { + sendMsgFailNumSum.incrementAndGet(); + } + + public void recordSendMsgDiscard() { + sendMsgDiscardNumSum.incrementAndGet(); + } + + public void cleanSendMsgStat() { + sendMsgNumSum.set(0l); + sendMsgFailNumSum.set(0l); + } + + public long getSendMsgDiscardNumSum() { + return sendMsgDiscardNumSum.longValue(); + } + + //////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_PUSHMSG = "%15s : {\"maxPushMsgTPS\":\"%.1f\",\"avgPushMsgTPS\":\"%.1f\"," + + " \"sum\":\"%s\", \"sumFail\":\"%s\", \"sumFailRate\":\"%.1f\", \"maxClientLatency\":\"%.1f\", \"avgClientLatency\":\"%.1f\"}"; + + private float wholePushCost = 0f; + + private AtomicLong wholePushRequestNum = new AtomicLong(0); + + private AtomicLong maxHttpPushLatency = new AtomicLong(0); + + private AtomicLong pushMsgNumPerSecond = new AtomicLong(0); + + private LinkedList pushMsgTPSSnapshots = new LinkedList(); + + private AtomicLong httpPushMsgNumSum = new AtomicLong(0); + + private AtomicLong httpPushFailNumSum = new AtomicLong(0); + + public void snapshotPushMsgTPS() { + Integer tps = pushMsgNumPerSecond.intValue(); + pushMsgTPSSnapshots.add(tps); + pushMsgNumPerSecond.set(0); + if (pushMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { + pushMsgTPSSnapshots.removeFirst(); + } + } + + public void recordHTTPPushTimeCost(long cost) { + wholePushRequestNum.incrementAndGet(); + wholePushCost = wholePushCost + cost; + if (cost > maxHttpPushLatency.longValue()) { + maxHttpPushLatency.set(cost); + } + } + + public float avgHTTPPushLatency() { + return (wholePushRequestNum.longValue() == 0l) ? 0f : wholePushCost / wholePushRequestNum.longValue(); + } + + public float maxHTTPPushLatency() { + return maxHttpPushLatency.floatValue(); + } + + public float maxPushMsgTPS() { + float tps = Collections.max(pushMsgTPSSnapshots); + return tps; + } + + public float avgPushMsgTPS() { + float tps = avg(pushMsgTPSSnapshots); + return tps; + } + + public void recordPushMsg() { + pushMsgNumPerSecond.incrementAndGet(); + httpPushMsgNumSum.incrementAndGet(); + } + + public long getHttpPushMsgNumSum() { + return httpPushMsgNumSum.longValue(); + } + + public long getHttpPushFailNumSum() { + return httpPushFailNumSum.longValue(); + } + + public float getHttpPushMsgFailRate() { + return (httpPushMsgNumSum.longValue() == 0l) ? 0f : httpPushFailNumSum.floatValue() / httpPushMsgNumSum.longValue(); + } + + public void recordHttpPushMsgFailed() { + sendMsgFailNumSum.incrementAndGet(); + } + + public void cleanHttpPushMsgStat() { + httpPushFailNumSum.set(0l); + httpPushMsgNumSum.set(0l); + wholeRequestNum.set(0l); + wholeCost = 0f; + maxCost.set(0l); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_BLOCKQ = "%15s : {\"batchMsgQ\":\"%s\",\"sendMsgQ\":\"%s\"," + + "\"pushMsgQ\":\"%s\",\"consumeRetryQ\":\"%s\"}"; + + /////////////////////////////////////////////////////////////////////////// + public static final String PROXY_MONITOR_FORMAT_MQ_CLIENT = "%15s : {\"batchAvgSend2MQCost\":\"%.1f\", \"avgSend2MQCost\":\"%.1f\"}"; + + private float batchSend2MQWholeCost = 0f; + + private AtomicLong batchSend2MQNum = new AtomicLong(0); + + private float send2MQWholeCost = 0f; + + private AtomicLong send2MQNum = new AtomicLong(0); + + public void recordBatchSendMsgCost(long cost) { + batchSend2MQNum.incrementAndGet(); + batchSend2MQWholeCost = batchSend2MQWholeCost + cost; + } + + public float avgBatchSendMsgCost() { + float cost = (batchSend2MQNum.intValue() == 0) ? 0f : batchSend2MQWholeCost / batchSend2MQNum.intValue(); + return cost; + } + + public void recordSendMsgCost(long cost) { + send2MQNum.incrementAndGet(); + send2MQWholeCost = send2MQWholeCost + cost; + } + + public float avgSendMsgCost() { + float cost = (send2MQNum.intValue() == 0) ? 0f : send2MQWholeCost / send2MQNum.intValue(); + return cost; + } + + public void send2MQStatInfoClear() { + batchSend2MQWholeCost = 0f; + batchSend2MQNum.set(0l); + send2MQWholeCost = 0f; + send2MQNum.set(0l); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/TopicMetrics.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/TopicMetrics.java new file mode 100644 index 0000000000..0f9f526746 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/TopicMetrics.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/http/TopicMetrics.java +package cn.webank.emesher.metrics.http; + +import cn.webank.emesher.boot.ProxyHTTPServer; +======== +package com.webank.runtime.metrics.http; + +import com.webank.runtime.boot.ProxyHTTPServer; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/metrics/http/TopicMetrics.java +import com.codahale.metrics.MetricRegistry; + +public class TopicMetrics { + + private ProxyHTTPServer proxyHTTPServer; + private MetricRegistry metricRegistry; + + public TopicMetrics(ProxyHTTPServer proxyHTTPServer, MetricRegistry metricRegistry) { + this.proxyHTTPServer = proxyHTTPServer; + this.metricRegistry = metricRegistry; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/tcp/ProxyTcpMonitor.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/tcp/ProxyTcpMonitor.java new file mode 100644 index 0000000000..16a189b07b --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/tcp/ProxyTcpMonitor.java @@ -0,0 +1,181 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/metrics/tcp/ProxyTcpMonitor.java +package cn.webank.emesher.metrics.tcp; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.ProxyTcpConnectionHandler; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.emesher.metrics.MonitorMetricConstants; +import cn.webank.emesher.threads.ThreadPoolHelper; +======== +package com.webank.runtime.metrics.tcp; + +import com.webank.runtime.boot.ProxyTCPServer; +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.tcp.client.ProxyTcpConnectionHandler; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.runtime.metrics.MonitorMetricConstants; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/metrics/tcp/ProxyTcpMonitor.java +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetSocketAddress; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +public class ProxyTcpMonitor { + + private ProxyTCPServer proxyTCPServer; + + private final Logger tcpLogger = LoggerFactory.getLogger("tcpMonitor"); + + private final Logger appLogger = LoggerFactory.getLogger("appMonitor"); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static int delay = 60 * 1000; + + private static int period = 60 * 1000; + + private static int PRINT_THREADPOOLSTATE_INTERVAL = 1; + + private AtomicInteger client2proxyMsgNum; + private AtomicInteger proxy2mqMsgNum; + private AtomicInteger mq2proxyMsgNum; + private AtomicInteger proxy2clientMsgNum; + + private int client2proxyTPS; + private int proxy2clientTPS; + private int proxy2mqTPS; + private int mq2proxyTPS; + private int allTPS; + private int subTopicNum; + + public ScheduledFuture monitorTpsTask; + + public ScheduledFuture monitorThreadPoolTask; + + public ProxyTcpMonitor(ProxyTCPServer proxyTCPServer) { + this.proxyTCPServer = proxyTCPServer; + } + + public void init() throws Exception { + this.client2proxyMsgNum = new AtomicInteger(0); + this.proxy2mqMsgNum = new AtomicInteger(0); + this.mq2proxyMsgNum = new AtomicInteger(0); + this.proxy2clientMsgNum = new AtomicInteger(0); + logger.info("ProxyTcpMonitor inited......"); + } + + public void start() throws Exception { + monitorTpsTask = proxyTCPServer.scheduler.scheduleAtFixedRate((new Runnable() { + @Override + public void run() { + int msgNum = client2proxyMsgNum.intValue(); + client2proxyMsgNum = new AtomicInteger(0); + client2proxyTPS = 1000 * msgNum / period; + + msgNum = proxy2clientMsgNum.intValue(); + proxy2clientMsgNum = new AtomicInteger(0); + proxy2clientTPS = 1000 * msgNum / period; + + msgNum = proxy2mqMsgNum.intValue(); + proxy2mqMsgNum = new AtomicInteger(0); + proxy2mqTPS = 1000 * msgNum / period; + + msgNum = mq2proxyMsgNum.intValue(); + mq2proxyMsgNum = new AtomicInteger(0); + mq2proxyTPS = 1000 * msgNum / period; + + allTPS = client2proxyTPS + proxy2clientTPS; + + //count topics subscribed by client in this proxy + ConcurrentHashMap sessionMap = proxyTCPServer.getClientSessionGroupMapping().getSessionMap(); + Iterator sessionIterator = sessionMap.values().iterator(); + Set topicSet = new HashSet<>(); + while (sessionIterator.hasNext()) { + Session session = sessionIterator.next(); + AtomicLong deliveredMsgsCount = session.getPusher().getPushContext().deliveredMsgsCount; + AtomicLong deliveredFailCount = session.getPusher().getPushContext().deliverFailMsgsCount; + AtomicLong ackedMsgsCount = session.getPusher().getPushContext().ackedMsgsCount; + int unAckMsgsCount = session.getPusher().getPushContext().getTotalUnackMsgs(); + int sendTopics = session.getSessionContext().sendTopics.size(); + int subscribeTopics = session.getSessionContext().subscribeTopics.size(); + + tcpLogger.info("session|deliveredFailCount={}|deliveredMsgsCount={}|ackedMsgsCount={}|unAckMsgsCount={}|sendTopics={}|subscribeTopics={}|user={}", + deliveredFailCount.longValue(), deliveredMsgsCount.longValue(), ackedMsgsCount.longValue(), + unAckMsgsCount, sendTopics, subscribeTopics, session.getClient()); + + topicSet.addAll(session.getSessionContext().subscribeTopics.keySet()); + } + subTopicNum = topicSet.size(); + + appLogger.info(String.format(MonitorMetricConstants.PROXY_MONITOR_FORMAT_COMMON, ProxyConstants.PROTOCOL_TCP, MonitorMetricConstants.CLIENT_2_PROXY_TPS, client2proxyTPS)); + appLogger.info(String.format(MonitorMetricConstants.PROXY_MONITOR_FORMAT_COMMON, ProxyConstants.PROTOCOL_TCP, MonitorMetricConstants.PROXY_2_MQ_TPS, proxy2mqTPS)); + appLogger.info(String.format(MonitorMetricConstants.PROXY_MONITOR_FORMAT_COMMON, ProxyConstants.PROTOCOL_TCP, MonitorMetricConstants.MQ_2_PROXY_TPS, mq2proxyTPS)); + appLogger.info(String.format(MonitorMetricConstants.PROXY_MONITOR_FORMAT_COMMON, ProxyConstants.PROTOCOL_TCP, MonitorMetricConstants.PROXY_2_CLIENT_TPS, proxy2clientTPS)); + appLogger.info(String.format(MonitorMetricConstants.PROXY_MONITOR_FORMAT_COMMON, ProxyConstants.PROTOCOL_TCP, MonitorMetricConstants.ALL_TPS, allTPS)); + appLogger.info(String.format(MonitorMetricConstants.PROXY_MONITOR_FORMAT_COMMON, ProxyConstants.PROTOCOL_TCP, MonitorMetricConstants.CONNECTION, ProxyTcpConnectionHandler.connections)); + appLogger.info(String.format(MonitorMetricConstants.PROXY_MONITOR_FORMAT_COMMON, ProxyConstants.PROTOCOL_TCP, MonitorMetricConstants.SUB_TOPIC_NUM, subTopicNum)); + } + }), delay, period, TimeUnit.MILLISECONDS); + + monitorThreadPoolTask = proxyTCPServer.scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + ThreadPoolHelper.printThreadPoolState(); + proxyTCPServer.getProxyTcpRetryer().printRetryThreadPoolState(); + + //monitor retry queue size + int retrySize = proxyTCPServer.getProxyTcpRetryer().getRetrySize(); + appLogger.info(String.format(MonitorMetricConstants.PROXY_MONITOR_FORMAT_COMMON, ProxyConstants.PROTOCOL_TCP, MonitorMetricConstants.RETRY_QUEUE_SIZE, retrySize)); + } + }, 10, PRINT_THREADPOOLSTATE_INTERVAL, TimeUnit.SECONDS); + logger.info("ProxyTcpMonitor started......"); + } + + public void shutdown() throws Exception { + monitorTpsTask.cancel(true); + monitorThreadPoolTask.cancel(true); + logger.info("ProxyTcpMonitor shutdown......"); + } + + public AtomicInteger getClient2proxyMsgNum() { + return client2proxyMsgNum; + } + + public AtomicInteger getProxy2mqMsgNum() { + return proxy2mqMsgNum; + } + + public AtomicInteger getMq2proxyMsgNum() { + return mq2proxyMsgNum; + } + + public AtomicInteger getProxy2clientMsgNum() { + return proxy2clientMsgNum; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/DelegatedExecutorService.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/DelegatedExecutorService.java new file mode 100644 index 0000000000..d027503afc --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/DelegatedExecutorService.java @@ -0,0 +1,96 @@ +/* + * 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 cn.webank.emesher.threads; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.AbstractExecutorService; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +class DelegatedExecutorService extends AbstractExecutorService { + private final ExecutorService e; + + DelegatedExecutorService(ExecutorService executor) { + e = executor; + } + + public void execute(Runnable command) { + e.execute(command); + } + + public void shutdown() { + e.shutdown(); + } + + public List shutdownNow() { + return e.shutdownNow(); + } + + public boolean isShutdown() { + return e.isShutdown(); + } + + public boolean isTerminated() { + return e.isTerminated(); + } + + public boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException { + return e.awaitTermination(timeout, unit); + } + + public Future submit(Runnable task) { + return e.submit(task); + } + + public Future submit(Callable task) { + return e.submit(task); + } + + public Future submit(Runnable task, T result) { + return e.submit(task, result); + } + + public List> invokeAll(Collection> tasks) + throws InterruptedException { + return e.invokeAll(tasks); + } + + public List> invokeAll(Collection> tasks, + long timeout, TimeUnit unit) + throws InterruptedException { + return e.invokeAll(tasks, timeout, unit); + } + + public T invokeAny(Collection> tasks) + throws InterruptedException, ExecutionException { + return e.invokeAny(tasks); + } + + public T invokeAny(Collection> tasks, + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return e.invokeAny(tasks, timeout, unit); + } + +} \ No newline at end of file diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/DelegatedScheduledExecutorService.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/DelegatedScheduledExecutorService.java new file mode 100644 index 0000000000..df30455823 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/DelegatedScheduledExecutorService.java @@ -0,0 +1,50 @@ +/* + * 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 cn.webank.emesher.threads; + +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +class DelegatedScheduledExecutorService + extends DelegatedExecutorService + implements ScheduledExecutorService { + private final ScheduledExecutorService e; + + DelegatedScheduledExecutorService(ScheduledExecutorService executor) { + super(executor); + e = executor; + } + + public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + return e.schedule(command, delay, unit); + } + + public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { + return e.schedule(callable, delay, unit); + } + + public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + return e.scheduleAtFixedRate(command, initialDelay, period, unit); + } + + public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { + return e.scheduleWithFixedDelay(command, initialDelay, delay, unit); + } +} \ No newline at end of file diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/ProxyThreadFactoryImpl.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/ProxyThreadFactoryImpl.java new file mode 100644 index 0000000000..2f10a05bdc --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/ProxyThreadFactoryImpl.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/threads/ProxyThreadFactoryImpl.java +package cn.webank.emesher.threads; +======== +package com.webank.runtime.util; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/util/ProxyThreadFactoryImpl.java + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicLong; + +public class ProxyThreadFactoryImpl implements ThreadFactory { + private final AtomicLong threadIndex = new AtomicLong(0); + private final String threadNamePrefix; + private Boolean isDaemonSpecified = null; + + public ProxyThreadFactoryImpl(final String threadNamePrefix) { + this.threadNamePrefix = threadNamePrefix; + } + + public ProxyThreadFactoryImpl(final String threadNamePrefix, final boolean isDaemonSpecified) { + this.threadNamePrefix = threadNamePrefix; + this.isDaemonSpecified = isDaemonSpecified; + } + + public String getThreadNamePrefix() { + return threadNamePrefix; + } + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, threadNamePrefix +'-'+ this.threadIndex.incrementAndGet()); + if (isDaemonSpecified != null) { + t.setDaemon(isDaemonSpecified); + } + return t; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedEventExecutorGroup.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedEventExecutorGroup.java new file mode 100644 index 0000000000..acd1b11af6 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedEventExecutorGroup.java @@ -0,0 +1,95 @@ +/* + * 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 cn.webank.emesher.threads; + +import io.netty.util.concurrent.DefaultEventExecutorGroup; +import io.netty.util.concurrent.Future; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +public class SharedEventExecutorGroup extends DefaultEventExecutorGroup { + private boolean _stutdown = false; + + /** + * Create a new instance. + * + * @param nThreads the number of threads that will be used by this instance. + * @param threadFactory the ThreadFactory to use, or {@code null} if the default should be + * used. + */ + public SharedEventExecutorGroup(int nThreads, ThreadFactory threadFactory) { + super(nThreads, threadFactory); + } + + @Override + public Future shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) { + _stutdown = true; + return terminationFuture(); + } + + @Override + public Future terminationFuture() { + return null; + } + + @Deprecated + @Override + public void shutdown() { + _stutdown = true; + } + + @Override + public boolean isShuttingDown() { + return _stutdown; + + } + + @Override + public boolean isShutdown() { + return _stutdown; + } + + @Override + public boolean isTerminated() { + return _stutdown; + } + + public void shutdownInternel() { + super.shutdownGracefully(3, 10, TimeUnit.SECONDS); + } + + @Override + public Future shutdownGracefully() { + _stutdown = true; + return terminationFuture(); + } + + /** + * @deprecated {@link #shutdownGracefully(long, long, TimeUnit)} or {@link + * #shutdownGracefully()} instead. + */ + @SuppressWarnings("unchecked") + @Override + public List shutdownNow() { + _stutdown = true; + return Collections.EMPTY_LIST; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedExecutorService.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedExecutorService.java new file mode 100644 index 0000000000..148e5cc0eb --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedExecutorService.java @@ -0,0 +1,70 @@ +/* + * 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 cn.webank.emesher.threads; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutorService; + +public class SharedExecutorService extends DelegatedExecutorService { + private final String name; + boolean _shutdown = false; + + public SharedExecutorService(ExecutorService executor, String name) { + super(executor); + this.name = name; + } + + @Override + public void shutdown() { + _shutdown = true; + } + + @SuppressWarnings("unchecked") + @Override + public List shutdownNow() { + _shutdown = true; + return Collections.EMPTY_LIST; + } + + @Override + public boolean isShutdown() { + return _shutdown; + } + + @SuppressWarnings("Duplicates") + @Override + public boolean isTerminated() { + if (isShutdown()) { + Thread.yield(); + Thread.yield(); + Thread.yield(); + Thread.yield(); + return true; + } else { + return false; + } + } + + @Override + public String toString() { + return "SharedExecutorService{" + + "name='" + name + '\'' + + "} " + super.toString(); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedNioEventLoopGroup.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedNioEventLoopGroup.java new file mode 100644 index 0000000000..6bf5cc324a --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedNioEventLoopGroup.java @@ -0,0 +1,88 @@ +/* + * 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 cn.webank.emesher.threads; + +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.concurrent.Future; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +public class SharedNioEventLoopGroup extends NioEventLoopGroup { + private boolean _stutdown = false; + + public SharedNioEventLoopGroup(int nThreads, ThreadFactory threadFactory) { + super(nThreads, threadFactory); + } + + @Override + public Future shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) { + _stutdown = true; + return terminationFuture(); + } + + @Override + public Future terminationFuture() { + return null; + } + + @Deprecated + @Override + public void shutdown() { + _stutdown = true; + } + + @Override + public boolean isShuttingDown() { + return _stutdown; + + } + + @Override + public boolean isShutdown() { + return _stutdown; + } + + @Override + public boolean isTerminated() { + return _stutdown; + } + + public void shutdownInternel() { + super.shutdownGracefully(3, 10, TimeUnit.SECONDS); + } + + @Override + public Future shutdownGracefully() { + _stutdown = true; + return terminationFuture(); + } + + /** + * @deprecated {@link #shutdownGracefully(long, long, TimeUnit)} or {@link + * #shutdownGracefully()} instead. + */ + @SuppressWarnings("unchecked") + @Override + public List shutdownNow() { + _stutdown = true; + return Collections.EMPTY_LIST; + } +} \ No newline at end of file diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedScheduledExecutorService.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedScheduledExecutorService.java new file mode 100644 index 0000000000..9d00c7ffc4 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/SharedScheduledExecutorService.java @@ -0,0 +1,120 @@ +/* + * 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 cn.webank.emesher.threads; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class SharedScheduledExecutorService extends DelegatedScheduledExecutorService { + private final String name; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private CopyOnWriteArrayList> scheduledFutures = new CopyOnWriteArrayList(); + private boolean _shutdown = false; + public SharedScheduledExecutorService(ScheduledExecutorService executor, String name) { + super(executor); + this.name = name; + this.scheduleWithFixedDelay(new Runnable() { + @Override + public void run() { + int size = scheduledFutures.size(); + for (ScheduledFuture future : scheduledFutures) { + if (future.isDone() || future.isCancelled()) scheduledFutures.remove(future); + } + logger.debug("clean up SharedScheduledExecutorService.scheduledFutures. this={} [{}->{}]", this, size, scheduledFutures.size()); + } + }, 60 * 30, 60 * 30, TimeUnit.SECONDS); + } + + @Override + public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + ScheduledFuture sf = super.schedule(command, delay, unit); + scheduledFutures.add(sf); + return sf; + } + + @Override + public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { + ScheduledFuture sf = super.schedule(callable, delay, unit); + scheduledFutures.add(sf); + return sf; + } + + @Override + public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + ScheduledFuture sf = super.scheduleAtFixedRate(command, initialDelay, period, unit); + scheduledFutures.add(sf); + return sf; + } + + @Override + public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { + ScheduledFuture sf = super.scheduleWithFixedDelay(command, initialDelay, delay, unit); + scheduledFutures.add(sf); + return sf; + } + + @Override + public void shutdown() { + for (ScheduledFuture sf : scheduledFutures) { + sf.cancel(false); + } + _shutdown = true; + scheduledFutures.clear(); + } + + @SuppressWarnings("unchecked") + @Override + public List shutdownNow() { + this.shutdown(); + return Collections.EMPTY_LIST; + } + + @Override + public boolean isShutdown() { + return _shutdown; + } + + @SuppressWarnings("Duplicates") + @Override + public boolean isTerminated() { + if (isShutdown()) { + Thread.yield(); + Thread.yield(); + Thread.yield(); + Thread.yield(); + return true; + } else { + return false; + } + } + + @Override + public String toString() { + return "SharedExecutorService{" + + "name='" + name + '\'' + + "} " + super.toString(); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/ThreadPoolHelper.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/ThreadPoolHelper.java new file mode 100644 index 0000000000..617c0f4524 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/threads/ThreadPoolHelper.java @@ -0,0 +1,499 @@ +/* + * 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 cn.webank.emesher.threads; + +import cn.webank.emesher.boot.ProxyTCPServer; +import cn.webank.emesher.metrics.MonitorMetricConstants; +import com.google.common.collect.Lists; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.concurrent.DefaultEventExecutorGroup; +import org.apache.rocketmq.common.ThreadFactoryImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class ThreadPoolHelper { + private static final boolean enabled = Boolean.parseBoolean(System.getProperty("access.server.share.threads", "true")); + private static final int executorServicePoolSize = Integer.parseInt(System.getProperty("client.executor.corePoolSize", + String.valueOf(Runtime.getRuntime().availableProcessors()))); + private static final int scheduledExecutorServicePoolSize = Integer.parseInt(System.getProperty("client.schedule.corePoolSize", + String.valueOf(Runtime.getRuntime().availableProcessors()/2))); + private static final int mqClientInstanceExecutorServicePoolSize = Integer.parseInt(System.getProperty("client.instance.corePoolSize", + String.valueOf(Runtime.getRuntime().availableProcessors()/2))); + private static final int producerCheckExecutorPoolSize = Integer.parseInt(System.getProperty("client.checkExecutor.corePoolSize", + String.valueOf(Runtime.getRuntime().availableProcessors()/2))); + private static final int rebalanceImplExecutorServicePoolSize = Integer.parseInt(System.getProperty("client.rebalanceImpl.corePoolSize", + String.valueOf(Runtime.getRuntime().availableProcessors()/2))); + private static final int rebalanceServiceExecutorServicePoolSize = Integer.parseInt(System.getProperty("client.rebalanceService.corePoolSize", + String.valueOf(Runtime.getRuntime().availableProcessors()/4))); + private static final int pullMessageServiceExecutorServicePoolSize = Integer.parseInt(System.getProperty("client.pullMessage.corePoolSize", + String.valueOf(Runtime.getRuntime().availableProcessors()))); + + private static final Logger logger = LoggerFactory.getLogger("tcpMonitor"); + + private static final Logger appLogger = LoggerFactory.getLogger("appMonitor"); + + public static void printThreadPoolState() { + printState(executorService); + printState(scheduledExecutorService); + printState(mqClientInstanceExecutorService); + printState(producerCheckExecutorService); + printState(rebalanceImplExecutorService); + printState(rebalanceServiceExecutorService); + printState(pullMessageServiceExecutorService); + printState(pullMessageRetryServiceExecutorService); + printState(consumeMessageExecutor); + printState((ThreadPoolExecutor) ProxyTCPServer.taskHandleExecutorService); + printState((ThreadPoolExecutor) ProxyTCPServer.scheduler); + printState((ThreadPoolExecutor) ProxyTCPServer.traceLogExecutor); + printState((ThreadPoolExecutor) ProxyTCPServer.configCenterUpdateScheduler); + } + + public static void printState(ThreadPoolExecutor scheduledExecutorService) { + String threadPoolName = ((ProxyThreadFactoryImpl) scheduledExecutorService.getThreadFactory()).getThreadNamePrefix(); + appLogger.info(String.format(MonitorMetricConstants.PROXY_TCP_MONITOR_FORMAT_THREADPOOL, threadPoolName, MonitorMetricConstants.QUEUE_SIZE, scheduledExecutorService.getQueue().size())); + appLogger.info(String.format(MonitorMetricConstants.PROXY_TCP_MONITOR_FORMAT_THREADPOOL, threadPoolName, MonitorMetricConstants.POOL_SIZE, scheduledExecutorService.getPoolSize())); + appLogger.info(String.format(MonitorMetricConstants.PROXY_TCP_MONITOR_FORMAT_THREADPOOL, threadPoolName, MonitorMetricConstants.ACTIVE_COUNT, scheduledExecutorService.getActiveCount())); + appLogger.info(String.format(MonitorMetricConstants.PROXY_TCP_MONITOR_FORMAT_THREADPOOL, threadPoolName, MonitorMetricConstants.COMPLETED_TASK, scheduledExecutorService.getCompletedTaskCount())); + } + + /** + * 全局共享的ThreadPoolExecutor + */ + private static final ThreadPoolExecutor executorService = __initExecutorService("SharedExecutorService", executorServicePoolSize); + + /** + * 全局共享的ScheduledThreadPoolExecutor + */ + private static final ScheduledThreadPoolExecutor scheduledExecutorService = __initScheduledExecutorService + ("SharedScheduledExecutorService", scheduledExecutorServicePoolSize); + + /** + * 所有MQClientInstance共享的线程池 + */ + private static final ScheduledThreadPoolExecutor mqClientInstanceExecutorService = + __initScheduledExecutorService("MQClientInstanceExecutorService", mqClientInstanceExecutorServicePoolSize); + + /** + * 所有Producer共享的checkExecutor线程池 + */ + private static final ScheduledThreadPoolExecutor producerCheckExecutorService = + __initScheduledExecutorService("ProducerCheckExecutorService", producerCheckExecutorPoolSize); + + /** + * 对单topic进行负载均衡操作的线程池 + */ + private static final ThreadPoolExecutor rebalanceImplExecutorService = __initExecutorService + ("RebalanceImplExecutorService", rebalanceImplExecutorServicePoolSize); + + /** + * 对单个client进行负载均衡操作的线程池 + */ + private static final ScheduledThreadPoolExecutor rebalanceServiceExecutorService = __initScheduledExecutorService + ("RebalanceServiceExecutorService", rebalanceServiceExecutorServicePoolSize); + + /** + * client拉消息的线程池 + */ + private static final ScheduledThreadPoolExecutor pullMessageServiceExecutorService = __initScheduledExecutorService + ("PullMessageServiceExecutorService", pullMessageServiceExecutorServicePoolSize); + + /** + * client重试拉消息的线程池 + */ + private static final ScheduledThreadPoolExecutor pullMessageRetryServiceExecutorService = __initScheduledExecutorService + ("PullMessageRetryServiceExecutorService", pullMessageServiceExecutorServicePoolSize); + + /** + * ACCESS全局共享的调度线程池 + */ + private static final ScheduledThreadPoolExecutor accessScheduler = new ScheduledThreadPoolExecutor(20, new + ProxyThreadFactoryImpl("ProxyServerScheduler")); + + /** + * 用于上报rmb跟踪日志的线程池 + */ + private static final ScheduledThreadPoolExecutor traceLogUploadScheduler = new ScheduledThreadPoolExecutor(50, new + ProxyThreadFactoryImpl("TraceLogUploadScheduler")); + + private static final ThreadPoolHelper.ProxyServerThreadPool consumeMessageExecutor = new + ThreadPoolHelper.ProxyServerThreadPool( + 80, + 80, + 120, + TimeUnit.SECONDS, + new LinkedBlockingQueue<>(100_000), + new ProxyThreadFactoryImpl("SharedConsumeMessageThread") + ); + + private static NioEventLoopGroup nettyClientSelectors = new SharedNioEventLoopGroup(8, new + ProxyThreadFactoryImpl("AccessNettyClientSelector")); + + private static DefaultEventExecutorGroup nettyClientWorkerThreads = new SharedEventExecutorGroup(16, new + ProxyThreadFactoryImpl("AccessNettyClientWorkerThread")); + + private static ThreadPoolExecutor __initExecutorService(String namePrefix, int corePoolSize) { + return new ThreadPoolExecutor( + corePoolSize, + 300, + 120, + TimeUnit.SECONDS, + new LinkedBlockingQueue<>(50_000), + new ProxyThreadFactoryImpl(namePrefix) + ); + } + + private static ScheduledThreadPoolExecutor __initScheduledExecutorService(String namePrefix, int corePoolSize) { + ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor( + corePoolSize, + new ProxyThreadFactoryImpl(namePrefix) + ); + executor.setRemoveOnCancelPolicy(true); + executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); + executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + return executor; + } + + private static ExecutorService createSharedExecutorService(String name) { + return new SharedExecutorService(executorService, name); + } + + private static ScheduledExecutorService createSharedScheduledExecutorService(String name) { + return new SharedScheduledExecutorService(scheduledExecutorService, name); + } + + private static ScheduledExecutorService createMQClientInstanceExecutorService(String name) { + return new SharedScheduledExecutorService(mqClientInstanceExecutorService, name); + } + + private static ScheduledExecutorService createProducerCheckExecutorService(String name) { + return new SharedScheduledExecutorService(producerCheckExecutorService, name); + } + + private static ExecutorService createRebalanceImplExecutorService(String name) { + return new SharedExecutorService(rebalanceImplExecutorService, name); + } + + private static ScheduledExecutorService createRebalanceServiceExecutorService(String name) { + return new SharedScheduledExecutorService(rebalanceServiceExecutorService, name); + } + + private static ScheduledExecutorService createPullMessageServiceExecutorService(String name) { + return new SharedScheduledExecutorService(pullMessageServiceExecutorService, name); + } + + private static ScheduledExecutorService createPullMessageRetryServiceExecutorService(String name) { + return new SharedScheduledExecutorService(pullMessageRetryServiceExecutorService, name); + } + + private static ScheduledExecutorService createOriginalMQClientFactoryScheduledThread() { + return Executors.newSingleThreadScheduledExecutor(new ProxyThreadFactoryImpl + ("MQClientFactoryScheduledThread")); + } + + private static ScheduledExecutorService createOriginalUpdateCLInfoScheduledThread() { + return Executors.newSingleThreadScheduledExecutor(new ProxyThreadFactoryImpl("UpdateCLInfo")); + } + + private static ScheduledExecutorService createOriginalCleanUpRRResponseServiceScheduledThread() { + return Executors.newSingleThreadScheduledExecutor(new ProxyThreadFactoryImpl + ("CleanUp_RRResponse_Service_")); + } + + private static ScheduledExecutorService createOriginalMQClusterManageServiceScheduledThread() { + return Executors.newSingleThreadScheduledExecutor(new ProxyThreadFactoryImpl("MQClusterManageService_")); + } + + private static ScheduledExecutorService createOriginalClientHouseKeepingService() { + return Executors.newSingleThreadScheduledExecutor(new ProxyThreadFactoryImpl("ClientHouseKeepingService")); + } + + private static ScheduledExecutorService createOriginalCleanExpireMsgScheduledThreads() { + return Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("CleanExpireMsgScheduledThread_")); + } + + private static ScheduledExecutorService createOriginalConsumeMessageScheduledThreads() { + return Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("ConsumeMessageScheduledThread_")); + } + + private static ScheduledExecutorService createOriginalPullMessageServiceScheduledThreads() { + return Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "PullMessageServiceScheduledThread"); + } + }); + } + + private static ExecutorService createOriginalNettyClientPublicExecutor() { + return Executors.newFixedThreadPool(2, new ThreadFactory() { + private AtomicInteger threadIndex = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "NettyClientPublicExecutor_" + this.threadIndex.incrementAndGet()); + } + }); + } + + private static NioEventLoopGroup createOriginalNettyClientSelectors() { + return new NioEventLoopGroup(1, new ThreadFactory() { + private AtomicInteger threadIndex = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + return new Thread(r, String.format("NettyClientSelector_%d", + this.threadIndex.incrementAndGet())); + } + }); + } + + private static DefaultEventExecutorGroup createOriginalNettyClientWorkerThreads() { + return new DefaultEventExecutorGroup(// + 2,// nettyClientConfig.getClientWorkerThreads(), // + new ThreadFactory() { + private AtomicInteger threadIndex = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "NettyClientWorkerThread_" + this.threadIndex.incrementAndGet()); + } + }); + } + + private static ThreadPoolExecutor createOriginalConsumeMessageThreads() { + return new ThreadPoolExecutor(// + 20, //this.defaultMQPushConsumer.getConsumeThreadMin(),// + 60,// this.defaultMQPushConsumer.getConsumeThreadMax(),// + 1000 * 60,// + TimeUnit.MILLISECONDS,// + new LinkedBlockingQueue(),// this.consumeRequestQueue,// + new ThreadFactoryImpl("ConsumeMessageThread_")); + } + + public static ScheduledExecutorService getMQClientFactoryScheduledThread() { + if (enabled) + return createMQClientInstanceExecutorService("MQClientFactoryScheduledThread"); + else + return createOriginalMQClientFactoryScheduledThread(); + } + + public static ScheduledExecutorService getProducerCheckScheduledThread() { + return createProducerCheckExecutorService("ProducerCheckScheduledThread"); + } + + public static ScheduledExecutorService getUpdateCLInfoScheduledThread() { + if (enabled) + return createSharedScheduledExecutorService("UpdateCLInfo"); + else + return createOriginalUpdateCLInfoScheduledThread(); + } + + public static ScheduledExecutorService getCleanUpRRResponseServiceScheduledThread() { + if (enabled) + return createSharedScheduledExecutorService("CleanUp_RRResponse_Service_"); + else + return createOriginalCleanUpRRResponseServiceScheduledThread(); + } + + public static ScheduledExecutorService getMQClusterManageServiceScheduledThread() { + if (enabled) + return createSharedScheduledExecutorService("MQClusterManageService_"); + else + return createOriginalMQClusterManageServiceScheduledThread(); + } + + public static ExecutorService getClientExecutorService() { + if (enabled) + return createSharedExecutorService("MQClientThread_"); + else + throw new UnsupportedOperationException(); + } + + public static ScheduledExecutorService getClientScheduledExecutorService() { + if (enabled) + return createSharedScheduledExecutorService("MQClientScheduler_"); + else + throw new UnsupportedOperationException(); + } + + public static ScheduledExecutorService getPullMessageServiceScheduledThread() { + if (enabled) + return createPullMessageServiceExecutorService("PullMessageServiceScheduledThread"); + else + return createOriginalPullMessageServiceScheduledThreads(); + } + + public static ScheduledExecutorService getPullMessageRetryServiceScheduledThread() { + return createPullMessageRetryServiceExecutorService("PullMessageRetryServiceScheduledThread"); + } + + public static ExecutorService getNettyClientPublicExecutor() { + if (enabled) + return createSharedExecutorService("NettyClientPublicExecutor"); + else + return createOriginalNettyClientPublicExecutor(); + } + + public static NioEventLoopGroup getNettyClientSelectors() { + if (enabled) + return nettyClientSelectors; + else + return createOriginalNettyClientSelectors(); + } + + public static DefaultEventExecutorGroup getNettyClientWorkerThreads() { + if (enabled) + return nettyClientWorkerThreads; + else + return createOriginalNettyClientWorkerThreads(); + } + + public static ScheduledExecutorService getClientHouseKeepingService() { + if (enabled) + return createSharedScheduledExecutorService("ClientHouseKeepingService"); + else + return createOriginalClientHouseKeepingService(); + } + + public static ScheduledExecutorService getConsumeMessageScheduledThread() { + if (enabled) + return createSharedScheduledExecutorService("ConsumeMessageScheduledThread"); + else + return createOriginalConsumeMessageScheduledThreads(); + } + + public static ScheduledExecutorService getCleanExpireMsgScheduledThread() { + if (enabled) { + return createSharedScheduledExecutorService("CleanExpireMsgScheduledThread"); + } else { + return createOriginalCleanExpireMsgScheduledThreads(); + } + } + + public static ExecutorService getConsumeMessageThreads() { + if (enabled) + return createSharedExecutorService("ConsumeMessageThread_"); + else + return createOriginalConsumeMessageThreads(); + } + + public static ScheduledExecutorService getRebalanceServiceExecutorService() { + return createRebalanceServiceExecutorService("RebalanceServiceThread"); + } + + public static ExecutorService getRebalanceImplExecutorService() { + return createRebalanceImplExecutorService("RebalanceByTopicThread"); + } + + public static ProxyServerThreadPool getConsumeMessageExecutor() { + return consumeMessageExecutor; + } + + public static void shutdownSharedScheduledExecutorService() { + scheduledExecutorService.shutdown(); + } + + public static void shutdownRebalanceImplExecutorService() { + rebalanceImplExecutorService.shutdown(); + } + + public static void shutdownRebalanceServiceExecutorService() { + rebalanceServiceExecutorService.shutdown(); + } + + public static void shutdownMQClientInstanceExecutorService() { + mqClientInstanceExecutorService.shutdown(); + } + + public static void shutdownProducerCheckExecutorService(){ + producerCheckExecutorService.shutdown(); + } + + public static void shutdownPullMessageServiceExecutorService() { + pullMessageServiceExecutorService.shutdown(); + } + + public static void shutdownPullMessageRetryServiceExecutorService() { + pullMessageRetryServiceExecutorService.shutdown(); + } + + public static void shutdownExecutorService() { + executorService.shutdown(); + } + + + public static void shutdownConsumeMessageExecutor() { + consumeMessageExecutor.shutdownGracefully(); + } + + public static void shutdownNettyClientWorkerThread() { + if (nettyClientWorkerThreads instanceof SharedEventExecutorGroup) { + ((SharedEventExecutorGroup) nettyClientWorkerThreads).shutdownInternel(); + } else { + nettyClientWorkerThreads.shutdownGracefully(); + } + } + + public static void shutdownNettyClientSelector() { + if (nettyClientSelectors instanceof SharedNioEventLoopGroup) { + ((SharedNioEventLoopGroup) nettyClientSelectors).shutdownInternel(); + } else { + nettyClientSelectors.shutdownGracefully(); + } + } + + public static class ProxyServerThreadPool extends ThreadPoolExecutor { + private boolean terminated = false; + + public ProxyServerThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, + BlockingQueue workQueue, ThreadFactory threadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); + } + + @Override + public void shutdown() { + terminated = true; + } + + @Override + public boolean isTerminated() { + return terminated; + } + + public void shutdownGracefully() { + super.shutdown(); + } + + public List shutdownNow() { + return Lists.newArrayList(); + } + } +} + diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/util/ProxyUtil.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/util/ProxyUtil.java new file mode 100644 index 0000000000..38f9716756 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/util/ProxyUtil.java @@ -0,0 +1,369 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/util/ProxyUtil.java +package cn.webank.emesher.util; + + +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.constants.ProxyVersion; +import cn.webank.eventmesh.common.ThreadUtil; +import cn.webank.eventmesh.common.protocol.tcp.AccessMessage; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +======== +package com.webank.runtime.util; + + +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.constants.ProxyVersion; +import com.webank.eventmesh.common.ThreadUtil; +import com.webank.eventmesh.common.protocol.tcp.AccessMessage; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/util/ProxyUtil.java +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Map; +import java.util.TimeZone; + +public class ProxyUtil { + + public static Logger logger = LoggerFactory.getLogger(ProxyUtil.class); + + public static String buildPushMsgSeqNo() { + return StringUtils.rightPad(String.valueOf(System.currentTimeMillis()), 6) + String.valueOf(RandomStringUtils.randomNumeric(4)); + } + + public static String buildProxyClientID(String clientGroup, String proxyRegion, String proxyCluster) { + return StringUtils.trim(clientGroup) + + "-" + StringUtils.trim(proxyRegion) + "(" + StringUtils.trim(proxyCluster) + ")" + + "-" + ProxyVersion.getCurrentVersionDesc() + + "-" + ThreadUtil.getPID(); + } + + public static String buildProxyTcpClientID(String clientSysId, String clientDcn, String purpose, String proxyCluster) { + return StringUtils.trim(clientSysId) + + "-" + StringUtils.trim(clientDcn) + + "-" + StringUtils.trim(purpose) + + "-" + StringUtils.trim(proxyCluster) + + "-" + ProxyVersion.getCurrentVersionDesc() + + "-" + ThreadUtil.getPID(); + } + + public static String buildProxyTcpRRReplyerProducerGroup() { + return "Proxy-Tcp-RRReplyer"; + } + + public static String buildProxyTcpRRReplyerClientID(String proxySysId, String proxyRegion, String proxyDcn, String proxyCluster) { + return proxySysId + + "-" + StringUtils.trim(proxyRegion) + + "-" + StringUtils.trim(proxyDcn) + + "-" + StringUtils.trim(proxyCluster) + + "-" + ProxyVersion.getCurrentVersionDesc() + + "-" + ThreadUtil.getPID() + + "-RRReplyer"; + //return ProxyVersion.getCurrentVersionDesc() + "-" + ThreadUtil.getPID() + "(" + proxyConfiguration.proxyCluster + ")"; + } + + public static String buildBroadcastClientConsumerGroup(String systemId, String dcn) { + return ProxyConstants.CONSUMER_GROUP_NAME_PREFIX + ProxyConstants.BROADCAST_PREFIX + systemId + "-" + dcn; + } + + public static String buildPersistentClientConsumerGroup(String systemId, String dcn) { + return ProxyConstants.CONSUMER_GROUP_NAME_PREFIX + systemId + "-" + dcn; + } + public static String buildClientGroup(String systemId, String dcn) { + return systemId + "-" + dcn; + } + + public static String buildClientProducerGroup(String systemId, String dcn) { + return ProxyConstants.PRODUCER_GROUP_NAME_PREFIX + systemId + "-" + dcn; + } + + public static String buildCCAddr(String str) { + return str + "/namesrvAddr"; + } + + public static String buildCCAddr(String str, String idc) { + return str + "/namesrvAddr/" + idc; + } + + public static boolean isValidRMBTopic(String topic) { + if (StringUtils.isEmpty(topic) || !StringUtils.contains(topic, "-")) { + return false; + } + + String[] args = StringUtils.split(topic, "-"); + if (ArrayUtils.getLength(args) != 5) { + return false; + } + + String s0e = args[1]; + if (!StringUtils.equalsIgnoreCase("s", s0e) && !StringUtils.equalsIgnoreCase("e", s0e)) { + return false; + } + + String service = args[2]; + if (!StringUtils.isNumeric(service)) { + return false; + } + + return true; + } + + public static String getServiceIDStr(String topic) { + if (!isValidRMBTopic(topic)) { + return ""; + } + + String[] args = StringUtils.split(topic, "-"); + return args[2]; + } + + public static String getPidStr(String topic) { + if (!isValidRMBTopic(topic)) { + return ""; + } + + String[] args = StringUtils.split(topic, "-"); + return args[3]; + } + + public static boolean isService(String topic) { + String serviceStr = getServiceIDStr(topic); + if (StringUtils.isEmpty(serviceStr)) { + return false; + } + return "0".equals(StringUtils.substring(serviceStr, 3, 4)); + } + + public static boolean isBroadcast(String topic) { + String serviceStr = getServiceIDStr(topic); + if (StringUtils.isEmpty(serviceStr)) { + return false; + } + String[] args = StringUtils.split(topic, "-"); + return "3".equals(StringUtils.substring(args[2], 3, 4)) || "4".equals(StringUtils.substring(args[2], 3, 4)); + } + + /** + * 自定义取堆栈 + * + * @param e + * @return + */ + public static String stackTrace(Throwable e) { + return stackTrace(e, 0); + } + + public static String stackTrace(Throwable e, int level) { + if (e == null) { + return null; + } + + StackTraceElement[] eles = e.getStackTrace(); + level = (level == 0) ? eles.length : level; + StringBuilder sb = new StringBuilder(); + sb.append(e.getMessage()).append(System.lineSeparator()); + int innerLevel = 0; + for (StackTraceElement ele : eles) { + sb.append(ele.toString()).append(System.lineSeparator()); + if (++innerLevel >= level) { + break; + } + } + return sb.toString(); + } + + public static ObjectMapper createJsoner() { + ObjectMapper jsonMapper = new ObjectMapper(); + jsonMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + jsonMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + jsonMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + jsonMapper.setTimeZone(TimeZone.getDefault()); + return jsonMapper; + } + + + /** + * 打印mq消息的一部分内容 + * + * @param accessMessage + * @return + */ + public static String printMqMessage(AccessMessage accessMessage) { + Map properties = accessMessage.getProperties(); + + String keys = properties.get(ProxyConstants.KEYS_UPPERCASE); + if (!StringUtils.isNotBlank(keys)) { + keys = properties.get(ProxyConstants.KEYS_LOWERCASE); + } + + String result = String.format("Message [topic=%s,TTL=%s,uniqueId=%s,bizSeq=%s]", accessMessage.getTopic(), + properties.get(ProxyConstants.TTL), properties.get(ProxyConstants.RR_REQUEST_UNIQ_ID), keys); + return result; + } + + public static String getMessageBizSeq(org.apache.rocketmq.common.message.Message msg) { + Map properties = msg.getProperties(); + + String keys = properties.get(ProxyConstants.KEYS_UPPERCASE); + if (!StringUtils.isNotBlank(keys)) { + keys = properties.get(ProxyConstants.KEYS_LOWERCASE); + } + return keys; + } + + public static org.apache.rocketmq.common.message.Message decodeMessage(AccessMessage accessMessage) { + org.apache.rocketmq.common.message.Message msg = new org.apache.rocketmq.common.message.Message(); + msg.setTopic(accessMessage.getTopic()); + msg.setBody(accessMessage.getBody().getBytes()); + msg.getProperty("init"); + for (Map.Entry property : accessMessage.getProperties().entrySet()) { + msg.getProperties().put(property.getKey(), property.getValue()); + } + return msg; + } + + public static AccessMessage encodeMessage(org.apache.rocketmq.common.message.Message msg) throws Exception { + AccessMessage accessMessage = new AccessMessage(); + accessMessage.setBody(new String(msg.getBody(), "UTF-8")); + accessMessage.setTopic(msg.getTopic()); + for (Map.Entry property : msg.getProperties().entrySet()) { + accessMessage.getProperties().put(property.getKey(), property.getValue()); + } + return accessMessage; + } + + public static String getLocalAddr() { + //priority of networkInterface when generating client ip + String priority = System.getProperty("networkInterface.priority", "bond1 preferList = new ArrayList(); + for (String eth : priority.split("<")) { + preferList.add(eth); + } + NetworkInterface preferNetworkInterface = null; + + try { + Enumeration enumeration1 = NetworkInterface.getNetworkInterfaces(); + while (enumeration1.hasMoreElements()) { + final NetworkInterface networkInterface = enumeration1.nextElement(); + if (!preferList.contains(networkInterface.getName())) { + continue; + } else if (preferNetworkInterface == null) { + preferNetworkInterface = networkInterface; + } + //get the networkInterface that has higher priority + else if (preferList.indexOf(networkInterface.getName()) + > preferList.indexOf(preferNetworkInterface.getName())) { + preferNetworkInterface = networkInterface; + } + } + + // Traversal Network interface to get the first non-loopback and non-private address + ArrayList ipv4Result = new ArrayList(); + ArrayList ipv6Result = new ArrayList(); + + if (preferNetworkInterface != null) { + logger.debug("use preferNetworkInterface:{}", preferNetworkInterface); + final Enumeration en = preferNetworkInterface.getInetAddresses(); + getIpResult(ipv4Result, ipv6Result, en); + } else { + logger.debug("no preferNetworkInterface"); + Enumeration enumeration = NetworkInterface.getNetworkInterfaces(); + while (enumeration.hasMoreElements()) { + final NetworkInterface networkInterface = enumeration.nextElement(); + final Enumeration en = networkInterface.getInetAddresses(); + getIpResult(ipv4Result, ipv6Result, en); + } + } + + // prefer ipv4 + if (!ipv4Result.isEmpty()) { + for (String ip : ipv4Result) { + if (ip.startsWith("127.0") || ip.startsWith("192.168")) { + continue; + } + + return ip; + } + + return ipv4Result.get(ipv4Result.size() - 1); + } else if (!ipv6Result.isEmpty()) { + return ipv6Result.get(0); + } + //If failed to find,fall back to localhost + final InetAddress localHost = InetAddress.getLocalHost(); + return normalizeHostAddress(localHost); + } catch (SocketException e) { + e.printStackTrace(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + + return null; + } + + public static String normalizeHostAddress(final InetAddress localHost) { + if (localHost instanceof Inet6Address) { + return "[" + localHost.getHostAddress() + "]"; + } else { + return localHost.getHostAddress(); + } + } + + private static void getIpResult(ArrayList ipv4Result, ArrayList ipv6Result, + Enumeration en) { + while (en.hasMoreElements()) { + final InetAddress address = en.nextElement(); + if (!address.isLoopbackAddress()) { + if (address instanceof Inet6Address) { + ipv6Result.add(normalizeHostAddress(address)); + } else { + ipv4Result.add(normalizeHostAddress(address)); + } + } + } + } + + public static String buildUserAgentClientId(UserAgent client){ + if(client == null){ + return null; + } + StringBuilder sb = new StringBuilder(); + sb.append(client.getSubsystem()).append("-") + .append(client.getDcn()).append("-") + .append(client.getPid()).append("-") + .append(client.getHost()).append(":").append(client.getPort()); + return sb.toString(); + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/util/ServerGlobal.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/util/ServerGlobal.java new file mode 100644 index 0000000000..abe9c3312f --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/util/ServerGlobal.java @@ -0,0 +1,46 @@ + +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/util/ServerGlobal.java +package cn.webank.emesher.util; +======== +package com.webank.runtime.util; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/util/ServerGlobal.java + +import java.util.concurrent.atomic.AtomicLong; + +public class ServerGlobal { + + private static class SerGlobalHolder { + private static ServerGlobal singleton = new ServerGlobal(); + } + + public static ServerGlobal getInstance() { + return SerGlobalHolder.singleton; + } + + private AtomicLong msgCounter = new AtomicLong(); + + public AtomicLong getMsgCounter() { + return msgCounter; + } + + public void setMsgCounter(AtomicLong msgCounter) { + this.msgCounter = msgCounter; + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/util/Utils.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/util/Utils.java new file mode 100644 index 0000000000..cf180aa345 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/util/Utils.java @@ -0,0 +1,202 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/util/Utils.java +package cn.webank.emesher.util; + +import cn.webank.emesher.constants.ProxyConstants; +import cn.webank.emesher.core.protocol.tcp.client.session.Session; +import cn.webank.emesher.core.protocol.tcp.client.session.SessionState; +import cn.webank.eventmesh.common.protocol.tcp.AccessMessage; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +======== +package com.webank.runtime.util; + +import com.webank.runtime.constants.ProxyConstants; +import com.webank.runtime.core.protocol.tcp.client.session.Session; +import com.webank.runtime.core.protocol.tcp.client.session.SessionState; +import com.webank.eventmesh.common.protocol.tcp.AccessMessage; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/util/Utils.java +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Map; + +public class Utils { + private final static Logger logger = LoggerFactory.getLogger(Utils.class); + private final static Logger messageLogger = LoggerFactory.getLogger("message"); + + /** + * 用于向客户端发送消息 + * + * @param pkg + * @param startTime + * @param ctx + * @param session + */ + public static void writeAndFlush(final Package pkg, long startTime, long taskExecuteTime, ChannelHandlerContext ctx, Session + session) { + try { + UserAgent user = session == null ? null : session.getClient(); + if (session != null && session.getSessionState().equals(SessionState.CLOSED)) { + logFailedMessageFlow(pkg, user, startTime, taskExecuteTime, new Exception("the session has been closed")); + return; + } + ctx.writeAndFlush(pkg).addListener( + new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (!future.isSuccess()) { + logFailedMessageFlow(future, pkg, user, startTime, taskExecuteTime); + } else { + logSucceedMessageFlow(pkg, user, startTime, taskExecuteTime); + + if (session != null) { + session.getClientGroupWrapper().get().getProxyTcpMonitor().getProxy2clientMsgNum().incrementAndGet(); + } + } + } + } + ); + } catch (Exception e) { + logger.error("exception while sending message to client", e); + } + } + + /** + * 打印发送失败的消息流水 + * + * @param future + * @param pkg + * @param user + * @param startTime + */ + public static void logFailedMessageFlow(ChannelFuture future, Package pkg, UserAgent user, long startTime, long taskExecuteTime) { + logFailedMessageFlow(pkg, user, startTime, taskExecuteTime, future.cause()); + } + + private static void logFailedMessageFlow(Package pkg, UserAgent user, long startTime, long taskExecuteTime, Throwable e) { + if (pkg.getBody() instanceof AccessMessage) { + messageLogger.error("pkg|proxy2c|failed|cmd={}|mqMsg={}|user={}|wait={}ms|cost={}ms|errMsg={}", pkg.getHeader().getCommand(), + printMqMessage((AccessMessage) pkg.getBody()), user, taskExecuteTime - startTime, System.currentTimeMillis() - startTime, e); + } else { + messageLogger.error("pkg|proxy2c|failed|cmd={}|pkg={}|user={}|wait={}ms|cost={}ms|errMsg={}", pkg.getHeader().getCommand(), + pkg, user, taskExecuteTime - startTime, System.currentTimeMillis() - startTime, e); + } + } + + /** + * 打印发送发成的消息流水 + * + * @param pkg + * @param user + * @param startTime + */ + public static void logSucceedMessageFlow(Package pkg, UserAgent user, long startTime, long taskExecuteTime) { + if (pkg.getBody() instanceof AccessMessage) { + messageLogger.info("pkg|proxy2c|cmd={}|mqMsg={}|user={}|wait={}ms|cost={}ms", pkg.getHeader().getCommand(), + printMqMessage((AccessMessage) pkg.getBody()), user, taskExecuteTime - startTime, System.currentTimeMillis() - startTime); + } else { + messageLogger.info("pkg|proxy2c|cmd={}|pkg={}|user={}|wait={}ms|cost={}ms", pkg.getHeader().getCommand(), pkg, + user, taskExecuteTime - startTime, System.currentTimeMillis() - startTime); + } + } + + public static org.apache.rocketmq.common.message.Message decodeMessage(AccessMessage accessMessage) { + org.apache.rocketmq.common.message.Message msg = new org.apache.rocketmq.common.message.Message(); + msg.setTopic(accessMessage.getTopic()); + msg.setBody(accessMessage.getBody().getBytes()); + msg.getProperty("init"); + for (Map.Entry property : accessMessage.getProperties().entrySet()) { + msg.getProperties().put(property.getKey(), property.getValue()); + } + return msg; + } + + public static AccessMessage encodeMessage(org.apache.rocketmq.common.message.Message msg) throws Exception { + AccessMessage accessMessage = new AccessMessage(); + accessMessage.setBody(new String(msg.getBody(), "UTF-8")); + accessMessage.setTopic(msg.getTopic()); + for (Map.Entry property : msg.getProperties().entrySet()) { + accessMessage.getProperties().put(property.getKey(), property.getValue()); + } + return accessMessage; + } + + public static org.apache.rocketmq.common.message.Message messageMapper(org.apache.rocketmq.common.message.Message + message) { + org.apache.rocketmq.common.message.Message msg = new org.apache.rocketmq.common.message.Message(); + msg.setTopic(message.getTopic()); + msg.setBody(message.getBody()); + msg.getProperty("init"); + for (Map.Entry property : message.getProperties().entrySet()) { + msg.getProperties().put(property.getKey(), property.getValue()); + } + return msg; + } + + /** + * 打印mq消息的一部分内容 + * + * @param accessMessage + * @return + */ + public static String printMqMessage(AccessMessage accessMessage) { + Map properties = accessMessage.getProperties(); + + String bizSeqNo = properties.get(ProxyConstants.KEYS_UPPERCASE); + if (!StringUtils.isNotBlank(bizSeqNo)) { + bizSeqNo = properties.get(ProxyConstants.KEYS_LOWERCASE); + } + + String result = String.format("Message [topic=%s,TTL=%s,uniqueId=%s,bizSeq=%s]", accessMessage + .getTopic(), properties.get(ProxyConstants.TTL), properties.get(ProxyConstants.RR_REQUEST_UNIQ_ID), bizSeqNo); + return result; + } + + /** + * 打印mq消息的一部分内容 + * + * @param message + * @return + */ + public static String printMqMessage(org.apache.rocketmq.common.message.Message message) { + Map properties = message.getProperties(); + String bizSeqNo = message.getKeys(); + String result = String.format("Message [topic=%s,TTL=%s,uniqueId=%s,bizSeq=%s]", message.getTopic() + , properties.get(ProxyConstants.TTL), properties.get(ProxyConstants.RR_REQUEST_UNIQ_ID), bizSeqNo); + return result; + } + + /** + * 根据topic获取serviceId + */ + public static String getServiceId(String topic) { + String[] topicStrArr = topic.split("-"); + if (topicStrArr.length >= 3) { + return topicStrArr[2]; + } else { + return null; + } + } +} diff --git a/eventmesh-emesher/src/main/java/cn/webank/emesher/util/ValueComparator.java b/eventmesh-emesher/src/main/java/cn/webank/emesher/util/ValueComparator.java new file mode 100644 index 0000000000..57d0836196 --- /dev/null +++ b/eventmesh-emesher/src/main/java/cn/webank/emesher/util/ValueComparator.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-emesher/src/main/java/cn/webank/emesher/util/ValueComparator.java +package cn.webank.emesher.util; +======== +package com.webank.runtime.util; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/util/ValueComparator.java + +import java.util.Comparator; +import java.util.Map; + +public class ValueComparator implements Comparator> { + @Override + public int compare(Map.Entry x, Map.Entry y) { + return x.getValue().intValue() - y.getValue().intValue(); + } +} diff --git a/eventmesh-emesher/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/eventmesh-emesher/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java new file mode 100644 index 0000000000..352fe7857e --- /dev/null +++ b/eventmesh-emesher/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java @@ -0,0 +1,1356 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.client.impl.factory; + +import cn.webank.emesher.threads.ThreadPoolHelper; +import org.apache.rocketmq.client.ClientConfig; +import org.apache.rocketmq.client.admin.MQAdminExtInner; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.impl.ClientRemotingProcessor; +import org.apache.rocketmq.client.impl.FindBrokerResult; +import org.apache.rocketmq.client.impl.MQAdminImpl; +import org.apache.rocketmq.client.impl.MQClientAPIImpl; +import org.apache.rocketmq.client.impl.MQClientManager; +import org.apache.rocketmq.client.impl.consumer.DefaultMQPullConsumerImpl; +import org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl; +import org.apache.rocketmq.client.impl.consumer.MQConsumerInner; +import org.apache.rocketmq.client.impl.consumer.ProcessQueue; +import org.apache.rocketmq.client.impl.consumer.PullMessageService; +import org.apache.rocketmq.client.impl.consumer.RebalanceService; +import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl; +import org.apache.rocketmq.client.impl.producer.MQProducerInner; +import org.apache.rocketmq.client.impl.producer.TopicPublishInfo; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.stat.ConsumerStatsManager; +import org.apache.rocketmq.common.MQVersion; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.ServiceState; +import org.apache.rocketmq.common.UtilAll; +import org.apache.rocketmq.common.constant.PermName; +import org.apache.rocketmq.common.filter.ExpressionType; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData; +import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.common.protocol.heartbeat.ProducerData; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.apache.rocketmq.remoting.netty.NettyClientConfig; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +import java.io.UnsupportedEncodingException; +import java.net.DatagramSocket; +import java.security.SecureRandom; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class MQClientInstance { + private final static long LOCK_TIMEOUT_MILLIS = 3000; + private final InternalLogger log = ClientLogger.getLog(); + private final ClientConfig clientConfig; + private final int instanceIndex; + private final String clientId; + private final long bootTimestamp = System.currentTimeMillis(); + private final ConcurrentMap producerTable = new ConcurrentHashMap(); + private final ConcurrentMap consumerTable = new ConcurrentHashMap(); + private final ConcurrentMap adminExtTable = new ConcurrentHashMap(); + private final NettyClientConfig nettyClientConfig; + private final MQClientAPIImpl mQClientAPIImpl; + private final MQAdminImpl mQAdminImpl; + private final ConcurrentMap topicRouteTable = new ConcurrentHashMap(); + private final Lock lockNamesrv = new ReentrantLock(); + private final Lock lockHeartbeat = new ReentrantLock(); + private final ConcurrentMap> brokerAddrTable = + new ConcurrentHashMap>(); + private final ConcurrentMap> brokerVersionTable = + new ConcurrentHashMap>(); + private final ScheduledExecutorService scheduledExecutorService = ThreadPoolHelper + .getMQClientFactoryScheduledThread(); + private final ClientRemotingProcessor clientRemotingProcessor; + private final PullMessageService pullMessageService; + private final RebalanceService rebalanceService; + private final DefaultMQProducer defaultMQProducer; + private final ConsumerStatsManager consumerStatsManager; + private final AtomicLong sendHeartbeatTimesTotal = new AtomicLong(0); + private ServiceState serviceState = ServiceState.CREATE_JUST; + private DatagramSocket datagramSocket; + private SecureRandom random = new SecureRandom(); + + public MQClientInstance(ClientConfig clientConfig, int instanceIndex, String clientId) { + this(clientConfig, instanceIndex, clientId, null); + } + + public MQClientInstance(ClientConfig clientConfig, int instanceIndex, String clientId, RPCHook rpcHook) { + this.clientConfig = clientConfig; + this.instanceIndex = instanceIndex; + this.nettyClientConfig = new NettyClientConfig(); + this.nettyClientConfig.setClientCallbackExecutorThreads(clientConfig.getClientCallbackExecutorThreads()); + this.nettyClientConfig.setUseTLS(clientConfig.isUseTLS()); + this.clientRemotingProcessor = new ClientRemotingProcessor(this); + this.mQClientAPIImpl = new MQClientAPIImpl(this.nettyClientConfig, this.clientRemotingProcessor, rpcHook, clientConfig); + + if (this.clientConfig.getNamesrvAddr() != null) { + this.mQClientAPIImpl.updateNameServerAddressList(this.clientConfig.getNamesrvAddr()); + log.info("user specified name server address: {}", this.clientConfig.getNamesrvAddr()); + } + + this.clientId = clientId; + + this.mQAdminImpl = new MQAdminImpl(this); + + this.pullMessageService = new PullMessageService(this); + + this.rebalanceService = new RebalanceService(this); + + this.defaultMQProducer = new DefaultMQProducer(MixAll.CLIENT_INNER_PRODUCER_GROUP); + this.defaultMQProducer.resetClientConfig(clientConfig); + + this.consumerStatsManager = new ConsumerStatsManager(this.scheduledExecutorService); + + log.info("Created a new client Instance, InstanceIndex:{}, ClientID:{}, ClientConfig:{}, ClientVersion:{}, SerializerType:{}", + this.instanceIndex, + this.clientId, + this.clientConfig, + MQVersion.getVersionDesc(MQVersion.CURRENT_VERSION), RemotingCommand.getSerializeTypeConfigInThisServer()); + } + + public static TopicPublishInfo topicRouteData2TopicPublishInfo(final String topic, final TopicRouteData route) { + TopicPublishInfo info = new TopicPublishInfo(); + info.setTopicRouteData(route); + if (route.getOrderTopicConf() != null && route.getOrderTopicConf().length() > 0) { + String[] brokers = route.getOrderTopicConf().split(";"); + for (String broker : brokers) { + String[] item = broker.split(":"); + int nums = Integer.parseInt(item[1]); + for (int i = 0; i < nums; i++) { + MessageQueue mq = new MessageQueue(topic, item[0], i); + info.getMessageQueueList().add(mq); + } + } + + info.setOrderTopic(true); + } else { + List qds = route.getQueueDatas(); + Collections.sort(qds); + for (QueueData qd : qds) { + if (PermName.isWriteable(qd.getPerm())) { + BrokerData brokerData = null; + for (BrokerData bd : route.getBrokerDatas()) { + if (bd.getBrokerName().equals(qd.getBrokerName())) { + brokerData = bd; + break; + } + } + + if (null == brokerData) { + continue; + } + + if (!brokerData.getBrokerAddrs().containsKey(MixAll.MASTER_ID)) { + continue; + } + + for (int i = 0; i < qd.getWriteQueueNums(); i++) { + MessageQueue mq = new MessageQueue(topic, qd.getBrokerName(), i); + info.getMessageQueueList().add(mq); + } + } + } + + info.setOrderTopic(false); + } + + return info; + } + + public static Set topicRouteData2TopicSubscribeInfo(final String topic, final TopicRouteData route) { + Set mqList = new HashSet(); + List qds = route.getQueueDatas(); + for (QueueData qd : qds) { + if (PermName.isReadable(qd.getPerm())) { + for (int i = 0; i < qd.getReadQueueNums(); i++) { + MessageQueue mq = new MessageQueue(topic, qd.getBrokerName(), i); + mqList.add(mq); + } + } + } + + return mqList; + } + + public void start() throws MQClientException { + + synchronized (this) { + switch (this.serviceState) { + case CREATE_JUST: + this.serviceState = ServiceState.START_FAILED; + // If not specified,looking address from name server + if (null == this.clientConfig.getNamesrvAddr()) { + this.mQClientAPIImpl.fetchNameServerAddr(); + } + // Start request-response channel + this.mQClientAPIImpl.start(); + // Start various schedule tasks + this.startScheduledTask(); + // Start pull service + this.pullMessageService.start(); + // Start rebalance service + this.rebalanceService.start(); + // Start push service + this.defaultMQProducer.getDefaultMQProducerImpl().start(false); + log.info("the client factory [{}] start OK", this.clientId); + this.serviceState = ServiceState.RUNNING; + break; + case RUNNING: + break; + case SHUTDOWN_ALREADY: + break; + case START_FAILED: + throw new MQClientException("The Factory object[" + this.getClientId() + "] has been created before, and failed.", null); + default: + break; + } + } + } + + private void startScheduledTask() { + //fixbug by easoncchen, can not fetch nameserver addrs period +// if (null == this.clientConfig.getNamesrvAddr()) { + this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { + + @Override + public void run() { + try { + MQClientInstance.this.mQClientAPIImpl.fetchNameServerAddr(); + } catch (Exception e) { + log.warn("ScheduledTask fetchNameServerAddr except", e); + } + } + }, 1000 * 10, 1000 * 60 * 2, TimeUnit.MILLISECONDS); +// } + + this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { + + @Override + public void run() { + try { + MQClientInstance.this.updateTopicRouteInfoFromNameServer(); + } catch (Exception e) { + log.warn("ScheduledTask updateTopicRouteInfoFromNameServer failed", e); + } + } + }, 10, this.clientConfig.getPollNameServerInterval(), TimeUnit.MILLISECONDS); + + this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { + + @Override + public void run() { + try { + MQClientInstance.this.cleanOfflineBroker(); + MQClientInstance.this.sendHeartbeatToAllBrokerWithLock(); + } catch (Exception e) { + log.warn("ScheduledTask sendHeartbeatToAllBroker except", e); + } + } + }, 1000, this.clientConfig.getHeartbeatBrokerInterval(), TimeUnit.MILLISECONDS); + + this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { + + @Override + public void run() { + try { + MQClientInstance.this.persistAllConsumerOffset(); + } catch (Exception e) { + log.warn("ScheduledTask persistAllConsumerOffset except", e); + } + } + }, 1000 * 10, this.clientConfig.getPersistConsumerOffsetInterval(), TimeUnit.MILLISECONDS); + } + + public String getClientId() { + return clientId; + } + + public void updateTopicRouteInfoFromNameServer() { + Set topicList = new HashSet(); + + // Consumer + { + Iterator> it = this.consumerTable.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + MQConsumerInner impl = entry.getValue(); + if (impl != null) { + Set subList = impl.subscriptions(); + if (subList != null) { + for (SubscriptionData subData : subList) { + topicList.add(subData.getTopic()); + } + } + } + } + } + + // Producer + { + Iterator> it = this.producerTable.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + MQProducerInner impl = entry.getValue(); + if (impl != null) { + Set lst = impl.getPublishTopicList(); + topicList.addAll(lst); + } + } + } + + for (String topic : topicList) { + this.updateTopicRouteInfoFromNameServer(topic); + } + } + + /** + * Remove offline broker + */ + private void cleanOfflineBroker() { + try { + if (this.lockNamesrv.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) + try { + ConcurrentHashMap> updatedTable = new ConcurrentHashMap>(); + + Iterator>> itBrokerTable = this.brokerAddrTable.entrySet().iterator(); + while (itBrokerTable.hasNext()) { + Entry> entry = itBrokerTable.next(); + String brokerName = entry.getKey(); + HashMap oneTable = entry.getValue(); + + HashMap cloneAddrTable = new HashMap(); + cloneAddrTable.putAll(oneTable); + + Iterator> it = cloneAddrTable.entrySet().iterator(); + while (it.hasNext()) { + Entry ee = it.next(); + String addr = ee.getValue(); + if (!this.isBrokerAddrExistInTopicRouteTable(addr)) { + it.remove(); + log.info("the broker addr[{} {}] is offline, remove it", brokerName, addr); + } + } + + if (cloneAddrTable.isEmpty()) { + itBrokerTable.remove(); + log.info("the broker[{}] name's host is offline, remove it", brokerName); + } else { + updatedTable.put(brokerName, cloneAddrTable); + } + } + + if (!updatedTable.isEmpty()) { + this.brokerAddrTable.putAll(updatedTable); + } + } finally { + this.lockNamesrv.unlock(); + } + } catch (InterruptedException e) { + log.warn("cleanOfflineBroker failed", e); + } + } + + public void checkClientInBroker() throws MQClientException { + Iterator> it = this.consumerTable.entrySet().iterator(); + + while (it.hasNext()) { + Entry entry = it.next(); + Set subscriptionInner = entry.getValue().subscriptions(); + if (subscriptionInner == null || subscriptionInner.isEmpty()) { + return; + } + + for (SubscriptionData subscriptionData : subscriptionInner) { + if (ExpressionType.isTagType(subscriptionData.getExpressionType())) { + continue; + } + // may need to check one broker every cluster... + // assume that the configs of every broker in cluster are the the same. + String addr = findBrokerAddrByTopic(subscriptionData.getTopic()); + + if (addr != null) { + try { + this.getMQClientAPIImpl().checkClientInBroker( + addr, entry.getKey(), this.clientId, subscriptionData, 3 * 1000 + ); + } catch (Exception e) { + if (e instanceof MQClientException) { + throw (MQClientException) e; + } else { + throw new MQClientException("Check client in brokererr maybe because you use " + + subscriptionData.getExpressionType() + " to filter message, but server has not been upgraded to support!" + + "This error would not affect the launch of consumer, but may has impact on message receiving if you " + + "have use the new features which are not supported by server, please check the log!", e); + } + } + } + } + } + } + + public void sendHeartbeatToAllBrokerWithLock() { + if (this.lockHeartbeat.tryLock()) { + try { + this.sendHeartbeatToAllBroker(); + this.uploadFilterClassSource(); + } catch (final Exception e) { + log.warn("sendHeartbeatToAllBroker except", e); + } finally { + this.lockHeartbeat.unlock(); + } + } else { + log.info("lock heartBeat, but failed."); + } + } + +// public void sendHeartbeatToAllBrokerWithLockAsync() { +// if (this.lockHeartbeat.tryLock()) { +// try { +// this.sendHeartbeatToAllBrokerAsync(); +// this.uploadFilterClassSource(); +// } catch (final Exception e) { +// log.warn("sendHeartbeatToAllBroker except", e); +// } finally { +// this.lockHeartbeat.unlock(); +// } +// } else { +// log.info("lock heartBeat, but failed."); +// } +// } + + private void persistAllConsumerOffset() { + Iterator> it = this.consumerTable.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + MQConsumerInner impl = entry.getValue(); + impl.persistConsumerOffset(); + } + } + + public void adjustThreadPool() { + Iterator> it = this.consumerTable.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + MQConsumerInner impl = entry.getValue(); + if (impl != null) { + try { + if (impl instanceof DefaultMQPushConsumerImpl) { + DefaultMQPushConsumerImpl dmq = (DefaultMQPushConsumerImpl) impl; + dmq.adjustThreadPool(); + } + } catch (Exception e) { + } + } + } + } + + public boolean updateTopicRouteInfoFromNameServer(final String topic) { + return updateTopicRouteInfoFromNameServer(topic, false, null); + } + + private boolean isBrokerAddrExistInTopicRouteTable(final String addr) { + Iterator> it = this.topicRouteTable.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + TopicRouteData topicRouteData = entry.getValue(); + List bds = topicRouteData.getBrokerDatas(); + for (BrokerData bd : bds) { + if (bd.getBrokerAddrs() != null) { + boolean exist = bd.getBrokerAddrs().containsValue(addr); + if (exist) + return true; + } + } + } + + return false; + } + +// private void sendHeartbeatToAllBrokerAsync() { +// final HeartbeatData heartbeatData = this.prepareHeartbeatData(); +// final boolean producerEmpty = heartbeatData.getProducerDataSet().isEmpty(); +// final boolean consumerEmpty = heartbeatData.getConsumerDataSet().isEmpty(); +// if (producerEmpty && consumerEmpty) { +// log.warn("sending heartbeat async, but no consumer and no producer"); +// return; +// } +// +// if (!this.brokerAddrTable.isEmpty()) { +// final long times = this.sendHeartbeatTimesTotal.getAndIncrement(); +// Iterator>> it = this.brokerAddrTable.entrySet().iterator(); +// while (it.hasNext()) { +// Entry> entry = it.next(); +// final String brokerName = entry.getKey(); +// HashMap oneTable = entry.getValue(); +// if (oneTable != null) { +// for (final Map.Entry entry1 : oneTable.entrySet()) { +// Long id = entry1.getKey(); +// final String addr = entry1.getValue(); +// if (addr != null) { +// if (consumerEmpty) { +// if (id != MixAll.MASTER_ID) +// continue; +// } +// +// try { +// this.mQClientAPIImpl.sendHearbeatAsync(addr, heartbeatData, 3000, new SendHeartbeatCallback() { +// +// @Override +// public void onSuccess(Integer version) { +// if (!MQClientInstance.this.brokerVersionTable.containsKey(brokerName)) { +// MQClientInstance.this.brokerVersionTable.put(brokerName, new HashMap(4)); +// } +// MQClientInstance.this.brokerVersionTable.get(brokerName).put(addr, version); +// if (times % 20 == 0) { +// log.info("send heart beat to broker[{} {} {}] async success", brokerName, entry1.getKey(), addr); +// log.debug(heartbeatData.toString()); +// } +// } +// +// @Override +// public void onException(Throwable e) { +// log.warn("send heartbeat async faild. {}", e); +// } +// }); +// } catch (Exception e) { +// if (this.isBrokerInNameServer(addr)) { +// log.info("send heart beat async to broker[{} {} {}] failed", brokerName, id, addr); +// } else { +// log.info("send heart beat async to broker[{} {} {}] failed, because the broker not up, forget it", brokerName, +// id, addr); +// } +// } +// } +// } +// } +// } +// } +// } + + public void sendHeartbeatToBrokerByTopicWithLock(String topic) { + if (this.lockHeartbeat.tryLock()) { + try { + this.sendHeartbeatToBrokerByTopic(topic); + this.uploadFilterClassSource(); + } catch (final Exception e) { + log.warn("sendHeartbeatToBroker by {} except", topic, e); + } finally { + this.lockHeartbeat.unlock(); + } + } else { + log.info("lock heartBeat, but failed."); + } + } + + private void sendHeartbeatToBrokerByTopic(String topic) { + final HeartbeatData heartbeatData = this.prepareHeartbeatData(); + final boolean producerEmpty = heartbeatData.getProducerDataSet().isEmpty(); + final boolean consumerEmpty = heartbeatData.getConsumerDataSet().isEmpty(); + if (producerEmpty && consumerEmpty) { + log.warn("sending heartbeat by {}, but no consumer and no producer", topic); + return; + } + + TopicRouteData topicRouteData = this.topicRouteTable.get(topic); + if (topicRouteData != null){ + if (topicRouteData.getBrokerDatas() != null && !topicRouteData.getBrokerDatas().isEmpty()){ + long times = this.sendHeartbeatTimesTotal.getAndIncrement(); + Iterator it = topicRouteData.getBrokerDatas().iterator(); + while (it.hasNext()) { + BrokerData entry = it.next(); + String brokerName = entry.getBrokerName(); + HashMap oneTable = entry.getBrokerAddrs(); + if (oneTable != null) { + for (Map.Entry entry1 : oneTable.entrySet()) { + Long id = entry1.getKey(); + String addr = entry1.getValue(); + if (addr != null) { + if (consumerEmpty) { + if (id != MixAll.MASTER_ID) + continue; + } + + try { + int version = this.mQClientAPIImpl.sendHearbeat(addr, heartbeatData, 3000); + if (!this.brokerVersionTable.containsKey(brokerName)) { + this.brokerVersionTable.put(brokerName, new HashMap(4)); + } + this.brokerVersionTable.get(brokerName).put(addr, version); + if (times % 20 == 0) { + log.info("send heart beat to broker[{} {} {}] by {} success", brokerName, id, addr, topic); + log.debug(heartbeatData.toString()); + } + } catch (Exception e) { + if (this.isBrokerInNameServer(addr)) { + log.info("send heart beat to broker[{} {} {}] by {} failed, {}", brokerName, id, addr, topic, e.getMessage()); + } else { + log.info("send heart beat to broker[{} {} {}] by {} failed, because the broker not up, forget it", brokerName, + id, addr, topic); + } + } + } + } + } + } + } + } + } + + private void sendHeartbeatToAllBroker() { + final HeartbeatData heartbeatData = this.prepareHeartbeatData(); + final boolean producerEmpty = heartbeatData.getProducerDataSet().isEmpty(); + final boolean consumerEmpty = heartbeatData.getConsumerDataSet().isEmpty(); + if (producerEmpty && consumerEmpty) { + log.warn("sending heartbeat, but no consumer and no producer"); + return; + } + + if (!this.brokerAddrTable.isEmpty()) { + long times = this.sendHeartbeatTimesTotal.getAndIncrement(); + Iterator>> it = this.brokerAddrTable.entrySet().iterator(); + while (it.hasNext()) { + Entry> entry = it.next(); + String brokerName = entry.getKey(); + HashMap oneTable = entry.getValue(); + if (oneTable != null) { + for (Map.Entry entry1 : oneTable.entrySet()) { + Long id = entry1.getKey(); + String addr = entry1.getValue(); + if (addr != null) { + if (consumerEmpty) { + if (id != MixAll.MASTER_ID) + continue; + } + + try { + int version = this.mQClientAPIImpl.sendHearbeat(addr, heartbeatData, 3000); + if (!this.brokerVersionTable.containsKey(brokerName)) { + this.brokerVersionTable.put(brokerName, new HashMap(4)); + } + this.brokerVersionTable.get(brokerName).put(addr, version); + if (times % 20 == 0) { + log.info("send heart beat to broker[{} {} {}] success", brokerName, id, addr); + log.debug(heartbeatData.toString()); + } + } catch (Exception e) { + if (this.isBrokerInNameServer(addr)) { + log.info("send heart beat to broker[{} {} {}] failed, {}", brokerName, id, addr, e.getMessage()); + } else { + log.info("send heart beat to broker[{} {} {}] failed, because the broker not up, forget it", brokerName, + id, addr); + } + } + } + } + } + } + } + } + + private void uploadFilterClassSource() { + Iterator> it = this.consumerTable.entrySet().iterator(); + while (it.hasNext()) { + Entry next = it.next(); + MQConsumerInner consumer = next.getValue(); + if (ConsumeType.CONSUME_PASSIVELY == consumer.consumeType()) { + Set subscriptions = consumer.subscriptions(); + for (SubscriptionData sub : subscriptions) { + if (sub.isClassFilterMode() && sub.getFilterClassSource() != null) { + final String consumerGroup = consumer.groupName(); + final String className = sub.getSubString(); + final String topic = sub.getTopic(); + final String filterClassSource = sub.getFilterClassSource(); + try { + this.uploadFilterClassToAllFilterServer(consumerGroup, className, topic, filterClassSource); + } catch (Exception e) { + log.warn("uploadFilterClassToAllFilterServer failed", e); + } + } + } + } + } + } + + public boolean updateTopicRouteInfoFromNameServer(final String topic, boolean isDefault, + DefaultMQProducer defaultMQProducer) { + try { + log.debug("updateTopicRouteInfoFromNameServer start, topic[{}] ", topic); + if (this.lockNamesrv.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) { + try { + TopicRouteData topicRouteData; + if (isDefault && defaultMQProducer != null) { + topicRouteData = this.mQClientAPIImpl.getDefaultTopicRouteInfoFromNameServer(defaultMQProducer.getCreateTopicKey(), + 1000 * 3); + if (topicRouteData != null) { + for (QueueData data : topicRouteData.getQueueDatas()) { + int queueNums = Math.min(defaultMQProducer.getDefaultTopicQueueNums(), data.getReadQueueNums()); + data.setReadQueueNums(queueNums); + data.setWriteQueueNums(queueNums); + } + } + } else { + topicRouteData = this.mQClientAPIImpl.getTopicRouteInfoFromNameServer(topic, 1000 * 3); + } + if (topicRouteData != null) { + TopicRouteData old = this.topicRouteTable.get(topic); + boolean changed = topicRouteDataIsChange(old, topicRouteData); + if (!changed) { + changed = this.isNeedUpdateTopicRouteInfo(topic); + } else { + log.info("the topic[{}] route info changed, old[{}] ,new[{}]", topic, old, topicRouteData); + } + + if (changed) { + TopicRouteData cloneTopicRouteData = topicRouteData.cloneTopicRouteData(); + + for (BrokerData bd : topicRouteData.getBrokerDatas()) { + this.brokerAddrTable.put(bd.getBrokerName(), bd.getBrokerAddrs()); + } + + // Update Pub info + { + TopicPublishInfo publishInfo = topicRouteData2TopicPublishInfo(topic, topicRouteData); + publishInfo.setHaveTopicRouterInfo(true); + Iterator> it = this.producerTable.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + MQProducerInner impl = entry.getValue(); + if (impl != null) { + impl.updateTopicPublishInfo(topic, publishInfo); + } + } + } + + // Update sub info + { + Set subscribeInfo = topicRouteData2TopicSubscribeInfo(topic, topicRouteData); + Iterator> it = this.consumerTable.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + MQConsumerInner impl = entry.getValue(); + if (impl != null) { + impl.updateTopicSubscribeInfo(topic, subscribeInfo); + } + } + } + log.info("topicRouteTable.put. Topic = {}, TopicRouteData[{}]", topic, cloneTopicRouteData); + this.topicRouteTable.put(topic, cloneTopicRouteData); + return true; + } + } else { + log.warn("updateTopicRouteInfoFromNameServer, getTopicRouteInfoFromNameServer return null, Topic: {}", topic); + } + } catch (Exception e) { + if (!topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX) && !topic.equals(MixAll.AUTO_CREATE_TOPIC_KEY_TOPIC)) { + log.warn("updateTopicRouteInfoFromNameServer topic[{}] failed, {}", topic, e.getMessage()); + } + } finally { + this.lockNamesrv.unlock(); + } + } else { + log.warn("updateTopicRouteInfoFromNameServer topic[{}] tryLock timeout {}ms", topic, LOCK_TIMEOUT_MILLIS); + } + } catch (InterruptedException e) { + log.warn("updateTopicRouteInfoFromNameServer topic[{}] failed, {}", topic, e.getMessage()); + } + + return false; + } + + private HeartbeatData prepareHeartbeatData() { + HeartbeatData heartbeatData = new HeartbeatData(); + + // clientID + heartbeatData.setClientID(this.clientId); + + // Consumer + for (Map.Entry entry : this.consumerTable.entrySet()) { + MQConsumerInner impl = entry.getValue(); + if (impl != null) { + ConsumerData consumerData = new ConsumerData(); + consumerData.setGroupName(impl.groupName()); + consumerData.setConsumeType(impl.consumeType()); + consumerData.setMessageModel(impl.messageModel()); + consumerData.setConsumeFromWhere(impl.consumeFromWhere()); + consumerData.getSubscriptionDataSet().addAll(impl.subscriptions()); + consumerData.setUnitMode(impl.isUnitMode()); + + heartbeatData.getConsumerDataSet().add(consumerData); + } + } + + // Producer + for (Map.Entry entry : this.producerTable.entrySet()) { + MQProducerInner impl = entry.getValue(); + if (impl != null) { + ProducerData producerData = new ProducerData(); + producerData.setGroupName(entry.getKey()); + + heartbeatData.getProducerDataSet().add(producerData); + } + } + + return heartbeatData; + } + + private boolean isBrokerInNameServer(final String brokerAddr) { + Iterator> it = this.topicRouteTable.entrySet().iterator(); + while (it.hasNext()) { + Entry itNext = it.next(); + List brokerDatas = itNext.getValue().getBrokerDatas(); + for (BrokerData bd : brokerDatas) { + boolean contain = bd.getBrokerAddrs().containsValue(brokerAddr); + if (contain) + return true; + } + } + + return false; + } + + private void uploadFilterClassToAllFilterServer(final String consumerGroup, final String fullClassName, + final String topic, + final String filterClassSource) throws UnsupportedEncodingException { + byte[] classBody = null; + int classCRC = 0; + try { + classBody = filterClassSource.getBytes(MixAll.DEFAULT_CHARSET); + classCRC = UtilAll.crc32(classBody); + } catch (Exception e1) { + log.warn("uploadFilterClassToAllFilterServer failed, ClassName: {} {}", // + fullClassName, // + RemotingHelper.exceptionSimpleDesc(e1)); + } + + TopicRouteData topicRouteData = this.topicRouteTable.get(topic); + if (topicRouteData != null + && topicRouteData.getFilterServerTable() != null && !topicRouteData.getFilterServerTable().isEmpty()) { + Iterator>> it = topicRouteData.getFilterServerTable().entrySet().iterator(); + while (it.hasNext()) { + Entry> next = it.next(); + List value = next.getValue(); + for (final String fsAddr : value) { + try { + this.mQClientAPIImpl.registerMessageFilterClass(fsAddr, consumerGroup, topic, fullClassName, classCRC, classBody, + 5000); + + log.info("register message class filter to {} OK, ConsumerGroup: {} Topic: {} ClassName: {}", fsAddr, consumerGroup, + topic, fullClassName); + + } catch (Exception e) { + log.warn("uploadFilterClassToAllFilterServer failed", e); + } + } + } + } else { + log.warn("register message class filter failed, because no filter server, ConsumerGroup: {} Topic: {} ClassName: {}", + consumerGroup, topic, fullClassName); + } + } + + private boolean topicRouteDataIsChange(TopicRouteData olddata, TopicRouteData nowdata) { + if (olddata == null || nowdata == null) + return true; + TopicRouteData old = olddata.cloneTopicRouteData(); + TopicRouteData now = nowdata.cloneTopicRouteData(); + Collections.sort(old.getQueueDatas()); + Collections.sort(old.getBrokerDatas()); + Collections.sort(now.getQueueDatas()); + Collections.sort(now.getBrokerDatas()); + return !old.equals(now); + + } + + private boolean isNeedUpdateTopicRouteInfo(final String topic) { + boolean result = false; + { + Iterator> it = this.producerTable.entrySet().iterator(); + while (it.hasNext() && !result) { + Entry entry = it.next(); + MQProducerInner impl = entry.getValue(); + if (impl != null) { + result = impl.isPublishTopicNeedUpdate(topic); + } + } + } + + { + Iterator> it = this.consumerTable.entrySet().iterator(); + while (it.hasNext() && !result) { + Entry entry = it.next(); + MQConsumerInner impl = entry.getValue(); + if (impl != null) { + result = impl.isSubscribeTopicNeedUpdate(topic); + } + } + } + + return result; + } + + public void shutdown() { + // Consumer + if (!this.consumerTable.isEmpty()) + return; + + // AdminExt + if (!this.adminExtTable.isEmpty()) + return; + + // Producer + if (this.producerTable.size() > 1) + return; + + synchronized (this) { + switch (this.serviceState) { + case CREATE_JUST: + break; + case RUNNING: + this.defaultMQProducer.getDefaultMQProducerImpl().shutdown(false); + + this.serviceState = ServiceState.SHUTDOWN_ALREADY; + this.pullMessageService.shutdown(true); + this.scheduledExecutorService.shutdown(); + this.mQClientAPIImpl.shutdown(); + this.rebalanceService.shutdown(); + + if (this.datagramSocket != null) { + this.datagramSocket.close(); + this.datagramSocket = null; + } + MQClientManager.getInstance().removeClientFactory(this.clientId); + log.info("the client factory [{}] shutdown OK", this.clientId); + break; + case SHUTDOWN_ALREADY: + break; + default: + break; + } + } + } + + public boolean registerConsumer(final String group, final MQConsumerInner consumer) { + if (null == group || null == consumer) { + return false; + } + + MQConsumerInner prev = this.consumerTable.putIfAbsent(group, consumer); + if (prev != null) { + log.warn("the consumer group[" + group + "] exist already."); + return false; + } + + return true; + } + + public void unregisterConsumer(final String group) { + this.consumerTable.remove(group); + this.unregisterClientWithLock(null, group); + } + + private void unregisterClientWithLock(final String producerGroup, final String consumerGroup) { + try { + if (this.lockHeartbeat.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) { + try { + this.unregisterClient(producerGroup, consumerGroup); + } catch (Exception e) { + log.warn("unregisterClient except", e); + } finally { + this.lockHeartbeat.unlock(); + } + } else { + log.warn("lock heartBeat, but failed."); + } + } catch (InterruptedException e) { + log.warn("unregisterClientWithLock failed", e); + } + } + + private void unregisterClient(final String producerGroup, final String consumerGroup) { + Iterator>> it = this.brokerAddrTable.entrySet().iterator(); + while (it.hasNext()) { + Entry> entry = it.next(); + String brokerName = entry.getKey(); + HashMap oneTable = entry.getValue(); + + if (oneTable != null) { + for (Map.Entry entry1 : oneTable.entrySet()) { + String addr = entry1.getValue(); + if (addr != null) { + try { + this.mQClientAPIImpl.unregisterClient(addr, this.clientId, producerGroup, consumerGroup, 3000); + log.info("unregister client[Producer: {} Consumer: {}] from broker[{} {} {}] success", producerGroup, consumerGroup, brokerName, entry1.getKey(), addr); + } catch (RemotingException e) { + log.warn("unregister client except from broker: " + addr, e); + } catch (InterruptedException e) { + log.warn("unregister client except from broker: " + addr, e); + } catch (MQBrokerException e) { + log.warn("unregister client except from broker: " + addr, e); + } + } + } + } + } + } + + public boolean registerProducer(final String group, final DefaultMQProducerImpl producer) { + if (null == group || null == producer) { + return false; + } + + MQProducerInner prev = this.producerTable.putIfAbsent(group, producer); + if (prev != null) { + log.warn("the producer group[{}] exist already.", group); + return false; + } + + return true; + } + + public void unregisterProducer(final String group) { + this.producerTable.remove(group); + this.unregisterClientWithLock(group, null); + } + + public boolean registerAdminExt(final String group, final MQAdminExtInner admin) { + if (null == group || null == admin) { + return false; + } + + MQAdminExtInner prev = this.adminExtTable.putIfAbsent(group, admin); + if (prev != null) { + log.warn("the admin group[{}] exist already.", group); + return false; + } + + return true; + } + + public void unregisterAdminExt(final String group) { + this.adminExtTable.remove(group); + } + + public void rebalanceImmediately() { + this.rebalanceService.wakeup(); + } + + public void doRebalance() { + for (Map.Entry entry : this.consumerTable.entrySet()) { + MQConsumerInner impl = entry.getValue(); + if (impl != null) { + try { + impl.doRebalance(); + } catch (Throwable e) { + log.warn("doRebalance except", e); + } + } + } + } + + public MQProducerInner selectProducer(final String group) { + return this.producerTable.get(group); + } + + public MQConsumerInner selectConsumer(final String group) { + return this.consumerTable.get(group); + } + + public FindBrokerResult findBrokerAddressInAdmin(final String brokerName) { + String brokerAddr = null; + boolean slave = false; + boolean found = false; + + HashMap map = this.brokerAddrTable.get(brokerName); + if (map != null && !map.isEmpty()) { + FOR_SEG: + for (Map.Entry entry : map.entrySet()) { + Long id = entry.getKey(); + brokerAddr = entry.getValue(); + if (brokerAddr != null) { + found = true; + if (MixAll.MASTER_ID == id) { + slave = false; + break FOR_SEG; + } else { + slave = true; + } + break; + + } + } // end of for + } + + if (found) { + return new FindBrokerResult(brokerAddr, slave, findBrokerVersion(brokerName, brokerAddr)); + } + + return null; + } + + public String findBrokerAddressInPublish(final String brokerName) { + HashMap map = this.brokerAddrTable.get(brokerName); + if (map != null && !map.isEmpty()) { + return map.get(MixAll.MASTER_ID); + } + + return null; + } + + public FindBrokerResult findBrokerAddressInSubscribe(// + final String brokerName, // + final long brokerId, // + final boolean onlyThisBroker// + ) { + String brokerAddr = null; + boolean slave = false; + boolean found = false; + + HashMap map = this.brokerAddrTable.get(brokerName); + if (map != null && !map.isEmpty()) { + brokerAddr = map.get(brokerId); + slave = brokerId != MixAll.MASTER_ID; + found = brokerAddr != null; + + if (!found && !onlyThisBroker) { + Entry entry = map.entrySet().iterator().next(); + brokerAddr = entry.getValue(); + slave = entry.getKey() != MixAll.MASTER_ID; + found = true; + } + } + + if (found) { + return new FindBrokerResult(brokerAddr, slave, findBrokerVersion(brokerName, brokerAddr)); + } + + return null; + } + + public int findBrokerVersion(String brokerName, String brokerAddr) { + if (this.brokerVersionTable.containsKey(brokerName)) { + if (this.brokerVersionTable.get(brokerName).containsKey(brokerAddr)) { + return this.brokerVersionTable.get(brokerName).get(brokerAddr); + } + } + return 0; + } + + public List findConsumerIdList(final String topic, final String group) { + String brokerAddr = this.findBrokerAddrByTopic(topic); + if (null == brokerAddr) { + this.updateTopicRouteInfoFromNameServer(topic); + brokerAddr = this.findBrokerAddrByTopic(topic); + } + + if (null != brokerAddr) { + try { + return this.mQClientAPIImpl.getConsumerIdListByGroup(brokerAddr, group, 3000); + } catch (Exception e) { + log.warn("getConsumerIdListByGroup failed, " + brokerAddr + " " + group, e); + } + } + + return null; + } + + public String findBrokerAddrByTopic(final String topic) { + TopicRouteData topicRouteData = this.topicRouteTable.get(topic); + if (topicRouteData != null) { + List brokers = topicRouteData.getBrokerDatas(); + if (!brokers.isEmpty()) { + int index = random.nextInt(brokers.size()); + BrokerData bd = brokers.get(index % brokers.size()); + return bd.selectBrokerAddr(); + } + } + + return null; + } + + public synchronized void resetOffset(String topic, String group, Map offsetTable) { + DefaultMQPushConsumerImpl consumer = null; + try { + MQConsumerInner impl = this.consumerTable.get(group); + if (impl != null && impl instanceof DefaultMQPushConsumerImpl) { + consumer = (DefaultMQPushConsumerImpl) impl; + } else { + log.info("[reset-offset] consumer dose not exist. group={}", group); + return; + } + consumer.suspend(); + + ConcurrentMap processQueueTable = consumer.getRebalanceImpl().getProcessQueueTable(); + for (Map.Entry entry : processQueueTable.entrySet()) { + MessageQueue mq = entry.getKey(); + if (topic.equals(mq.getTopic()) && offsetTable.containsKey(mq)) { + ProcessQueue pq = entry.getValue(); + pq.setDropped(true); + pq.clear(); + } + } + + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + // + } + + Iterator iterator = processQueueTable.keySet().iterator(); + while (iterator.hasNext()) { + MessageQueue mq = iterator.next(); + Long offset = offsetTable.get(mq); + if (topic.equals(mq.getTopic()) && offset != null) { + try { + consumer.updateConsumeOffset(mq, offset); + consumer.getRebalanceImpl().removeUnnecessaryMessageQueue(mq, processQueueTable.get(mq)); + iterator.remove(); + } catch (Exception e) { + log.warn("reset offset failed. group={}, {}", group, mq, e); + } + } + } + } finally { + if (consumer != null) { + consumer.resume(); + } + } + } + + public Map getConsumerStatus(String topic, String group) { + MQConsumerInner impl = this.consumerTable.get(group); + if (impl != null && impl instanceof DefaultMQPushConsumerImpl) { + DefaultMQPushConsumerImpl consumer = (DefaultMQPushConsumerImpl) impl; + return consumer.getOffsetStore().cloneOffsetTable(topic); + } else if (impl != null && impl instanceof DefaultMQPullConsumerImpl) { + DefaultMQPullConsumerImpl consumer = (DefaultMQPullConsumerImpl) impl; + return consumer.getOffsetStore().cloneOffsetTable(topic); + } else { + return Collections.EMPTY_MAP; + } + } + + public TopicRouteData getAnExistTopicRouteData(final String topic) { + return this.topicRouteTable.get(topic); + } + + public MQClientAPIImpl getMQClientAPIImpl() { + return mQClientAPIImpl; + } + + public MQAdminImpl getMQAdminImpl() { + return mQAdminImpl; + } + + public long getBootTimestamp() { + return bootTimestamp; + } + + public ScheduledExecutorService getScheduledExecutorService() { + return scheduledExecutorService; + } + + public PullMessageService getPullMessageService() { + return pullMessageService; + } + + public DefaultMQProducer getDefaultMQProducer() { + return defaultMQProducer; + } + + public ConcurrentMap getTopicRouteTable() { + return topicRouteTable; + } + + public ConsumeMessageDirectlyResult consumeMessageDirectly(final MessageExt msg, // + final String consumerGroup, // + final String brokerName) { + MQConsumerInner mqConsumerInner = this.consumerTable.get(consumerGroup); + if (null != mqConsumerInner) { + DefaultMQPushConsumerImpl consumer = (DefaultMQPushConsumerImpl) mqConsumerInner; + + ConsumeMessageDirectlyResult result = consumer.getConsumeMessageService().consumeMessageDirectly(msg, brokerName); + return result; + } + + return null; + } + + public ConsumerRunningInfo consumerRunningInfo(final String consumerGroup) { + MQConsumerInner mqConsumerInner = this.consumerTable.get(consumerGroup); + + ConsumerRunningInfo consumerRunningInfo = mqConsumerInner.consumerRunningInfo(); + + List nsList = this.mQClientAPIImpl.getRemotingClient().getNameServerAddressList(); + + StringBuilder strBuilder = new StringBuilder(); + if (nsList != null) { + for (String addr : nsList) { + strBuilder.append(addr).append(";"); + } + } + + String nsAddr = strBuilder.toString(); + consumerRunningInfo.getProperties().put(ConsumerRunningInfo.PROP_NAMESERVER_ADDR, nsAddr); + consumerRunningInfo.getProperties().put(ConsumerRunningInfo.PROP_CONSUME_TYPE, mqConsumerInner.consumeType().name()); + consumerRunningInfo.getProperties().put(ConsumerRunningInfo.PROP_CLIENT_VERSION, + MQVersion.getVersionDesc(MQVersion.CURRENT_VERSION)); + + return consumerRunningInfo; + } + + public ConsumerStatsManager getConsumerStatsManager() { + return consumerStatsManager; + } + + public NettyClientConfig getNettyClientConfig() { + return nettyClientConfig; + } + + public ClientConfig getClientConfig() { + return clientConfig; + } +} diff --git a/eventmesh-emesher/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java b/eventmesh-emesher/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java new file mode 100644 index 0000000000..e8be3ffdf6 --- /dev/null +++ b/eventmesh-emesher/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java @@ -0,0 +1,1244 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.client.impl.producer; + +import cn.webank.emesher.threads.ThreadPoolHelper; +import org.apache.rocketmq.client.QueryResult; +import org.apache.rocketmq.client.Validators; +import org.apache.rocketmq.client.common.ClientErrorCode; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.hook.CheckForbiddenContext; +import org.apache.rocketmq.client.hook.CheckForbiddenHook; +import org.apache.rocketmq.client.hook.SendMessageContext; +import org.apache.rocketmq.client.hook.SendMessageHook; +import org.apache.rocketmq.client.impl.CommunicationMode; +import org.apache.rocketmq.client.impl.MQClientManager; +import org.apache.rocketmq.client.impl.factory.MQClientInstance; +import org.apache.rocketmq.client.latency.MQFaultStrategy; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.LocalTransactionState; +import org.apache.rocketmq.client.producer.MessageQueueSelector; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.client.producer.TransactionCheckListener; +import org.apache.rocketmq.client.producer.TransactionListener; +import org.apache.rocketmq.client.producer.TransactionMQProducer; +import org.apache.rocketmq.client.producer.TransactionSendResult; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.ServiceState; +import org.apache.rocketmq.common.UtilAll; +import org.apache.rocketmq.common.help.FAQUrl; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageBatch; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageId; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.message.MessageType; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.apache.rocketmq.remoting.exception.RemotingConnectException; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; +import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException; + +import java.io.IOException; +import java.net.UnknownHostException; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; + +public class DefaultMQProducerImpl implements MQProducerInner { + private final InternalLogger log = ClientLogger.getLog(); + private final SecureRandom random = new SecureRandom(); + private final DefaultMQProducer defaultMQProducer; + private final ConcurrentMap topicPublishInfoTable = + new ConcurrentHashMap(); + private final ArrayList sendMessageHookList = new ArrayList(); + private final RPCHook rpcHook; + protected BlockingQueue checkRequestQueue; + protected ExecutorService checkExecutor; + private ServiceState serviceState = ServiceState.CREATE_JUST; + private MQClientInstance mQClientFactory; + private ArrayList checkForbiddenHookList = new ArrayList(); + private int zipCompressLevel = Integer.parseInt(System.getProperty(MixAll.MESSAGE_COMPRESS_LEVEL, "5")); + + private MQFaultStrategy mqFaultStrategy = new MQFaultStrategy(); + + public DefaultMQProducerImpl(final DefaultMQProducer defaultMQProducer) { + this(defaultMQProducer, null); + } + + public DefaultMQProducerImpl(final DefaultMQProducer defaultMQProducer, RPCHook rpcHook) { + this.defaultMQProducer = defaultMQProducer; + this.rpcHook = rpcHook; + } + + public void registerCheckForbiddenHook(CheckForbiddenHook checkForbiddenHook) { + this.checkForbiddenHookList.add(checkForbiddenHook); + log.info("register a new checkForbiddenHook. hookName={}, allHookSize={}", checkForbiddenHook.hookName(), + checkForbiddenHookList.size()); + } + + public void initTransactionEnv() { + TransactionMQProducer producer = (TransactionMQProducer) this.defaultMQProducer; + if (producer.getExecutorService() != null) { + this.checkExecutor = producer.getExecutorService(); + } else { + this.checkRequestQueue = new LinkedBlockingQueue(2000); + this.checkExecutor = ThreadPoolHelper.getProducerCheckScheduledThread(); + } + } + + public void destroyTransactionEnv() { + if (this.checkExecutor != null) { + this.checkExecutor.shutdown(); +// this.checkRequestQueue.clear(); + } + } + + public void registerSendMessageHook(final SendMessageHook hook) { + this.sendMessageHookList.add(hook); + log.info("register sendMessage Hook, {}", hook.hookName()); + } + + public void start() throws MQClientException { + this.start(true); + } + + public void start(final boolean startFactory) throws MQClientException { + switch (this.serviceState) { + case CREATE_JUST: + this.serviceState = ServiceState.START_FAILED; + + this.checkConfig(); + + if (!this.defaultMQProducer.getProducerGroup().equals(MixAll.CLIENT_INNER_PRODUCER_GROUP)) { + this.defaultMQProducer.changeInstanceNameToPID(); + } + + this.mQClientFactory = MQClientManager.getInstance().getAndCreateMQClientInstance(this.defaultMQProducer, rpcHook); + + boolean registerOK = mQClientFactory.registerProducer(this.defaultMQProducer.getProducerGroup(), this); + if (!registerOK) { + this.serviceState = ServiceState.CREATE_JUST; + throw new MQClientException("The producer group[" + this.defaultMQProducer.getProducerGroup() + + "] has been created before, specify another name please." + FAQUrl.suggestTodo(FAQUrl.GROUP_NAME_DUPLICATE_URL), + null); + } + + this.topicPublishInfoTable.put(this.defaultMQProducer.getCreateTopicKey(), new TopicPublishInfo()); + + if (startFactory) { + mQClientFactory.start(); + } + + log.info("the producer [{}] start OK. sendMessageWithVIPChannel={}", this.defaultMQProducer.getProducerGroup(), + this.defaultMQProducer.isSendMessageWithVIPChannel()); + this.serviceState = ServiceState.RUNNING; + break; + case RUNNING: + case START_FAILED: + case SHUTDOWN_ALREADY: + throw new MQClientException("The producer service state not OK, maybe started once, " + + this.serviceState + + FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK), + null); + default: + break; + } + + this.mQClientFactory.sendHeartbeatToAllBrokerWithLock(); + } + + private void checkConfig() throws MQClientException { + Validators.checkGroup(this.defaultMQProducer.getProducerGroup()); + + if (null == this.defaultMQProducer.getProducerGroup()) { + throw new MQClientException("producerGroup is null", null); + } + + if (this.defaultMQProducer.getProducerGroup().equals(MixAll.DEFAULT_PRODUCER_GROUP)) { + throw new MQClientException("producerGroup can not equal " + MixAll.DEFAULT_PRODUCER_GROUP + ", please specify another one.", + null); + } + } + + public void shutdown() { + this.shutdown(true); + } + + public void shutdown(final boolean shutdownFactory) { + switch (this.serviceState) { + case CREATE_JUST: + break; + case RUNNING: + this.mQClientFactory.unregisterProducer(this.defaultMQProducer.getProducerGroup()); + if (shutdownFactory) { + this.mQClientFactory.shutdown(); + } + + log.info("the producer [{}] shutdown OK", this.defaultMQProducer.getProducerGroup()); + this.serviceState = ServiceState.SHUTDOWN_ALREADY; + break; + case SHUTDOWN_ALREADY: + break; + default: + break; + } + } + + @Override + public Set getPublishTopicList() { + Set topicList = new HashSet(); + for (String key : this.topicPublishInfoTable.keySet()) { + topicList.add(key); + } + + return topicList; + } + + @Override + public boolean isPublishTopicNeedUpdate(String topic) { + TopicPublishInfo prev = this.topicPublishInfoTable.get(topic); + + return null == prev || !prev.ok(); + } + + @Override + public TransactionCheckListener checkListener() { + if (this.defaultMQProducer instanceof TransactionMQProducer) { + TransactionMQProducer producer = (TransactionMQProducer) defaultMQProducer; + return producer.getTransactionCheckListener(); + } + return null; + } + + @Override + public TransactionListener getCheckListener() { + if (this.defaultMQProducer instanceof TransactionMQProducer) { + TransactionMQProducer producer = (TransactionMQProducer) defaultMQProducer; + return producer.getTransactionListener(); + } + return null; + } + + + @Override + public void checkTransactionState(final String addr, final MessageExt msg, final CheckTransactionStateRequestHeader header) { + Runnable request = new Runnable() { + private final String brokerAddr = addr; + private final MessageExt message = msg; + private final CheckTransactionStateRequestHeader checkRequestHeader = header; + private final String group = DefaultMQProducerImpl.this.defaultMQProducer.getProducerGroup(); + + @Override + public void run() { + TransactionCheckListener transactionCheckListener = DefaultMQProducerImpl.this.checkListener(); + TransactionListener transactionListener = getCheckListener(); + if (transactionCheckListener != null || transactionListener != null) { + LocalTransactionState localTransactionState = LocalTransactionState.UNKNOW; + Throwable exception = null; + try { + if (transactionCheckListener != null) { + localTransactionState = transactionCheckListener.checkLocalTransactionState(message); + } else if (transactionListener != null) { + log.debug("Used new check API in transaction message"); + localTransactionState = transactionListener.checkLocalTransaction(message); + } else { + log.warn("CheckTransactionState, pick transactionListener by group[{}] failed", group); + } + } catch (Throwable e) { + log.error("Broker call checkTransactionState, but checkLocalTransactionState exception", e); + exception = e; + } + + this.processTransactionState( + localTransactionState, + group, + exception); + } else { + log.warn("CheckTransactionState, pick transactionCheckListener by group[{}] failed", group); + } + } + + private void processTransactionState( + final LocalTransactionState localTransactionState, + final String producerGroup, + final Throwable exception) { + final EndTransactionRequestHeader thisHeader = new EndTransactionRequestHeader(); + thisHeader.setCommitLogOffset(checkRequestHeader.getCommitLogOffset()); + thisHeader.setProducerGroup(producerGroup); + thisHeader.setTranStateTableOffset(checkRequestHeader.getTranStateTableOffset()); + thisHeader.setFromTransactionCheck(true); + + String uniqueKey = message.getProperties().get(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); + if (uniqueKey == null) { + uniqueKey = message.getMsgId(); + } + thisHeader.setMsgId(uniqueKey); + thisHeader.setTransactionId(checkRequestHeader.getTransactionId()); + switch (localTransactionState) { + case COMMIT_MESSAGE: + thisHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_COMMIT_TYPE); + break; + case ROLLBACK_MESSAGE: + thisHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_ROLLBACK_TYPE); + log.warn("when broker check, client rollback this transaction, {}", thisHeader); + break; + case UNKNOW: + thisHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_NOT_TYPE); + log.warn("when broker check, client does not know this transaction state, {}", thisHeader); + break; + default: + break; + } + + String remark = null; + if (exception != null) { + remark = "checkLocalTransactionState Exception: " + RemotingHelper.exceptionSimpleDesc(exception); + } + + try { + DefaultMQProducerImpl.this.mQClientFactory.getMQClientAPIImpl().endTransactionOneway(brokerAddr, thisHeader, remark, + 3000); + } catch (Exception e) { + log.warn("endTransactionOneway except", e); + } + } + }; + + this.checkExecutor.submit(request); + } + + @Override + public void updateTopicPublishInfo(final String topic, final TopicPublishInfo info) { + if (info != null && topic != null) { + TopicPublishInfo prev = this.topicPublishInfoTable.put(topic, info); + if (prev != null) { + log.info("updateTopicPublishInfo prev is not null, " + prev.toString()); + } + } + } + + @Override + public boolean isUnitMode() { + return this.defaultMQProducer.isUnitMode(); + } + + public void createTopic(String key, String newTopic, int queueNum) throws MQClientException { + createTopic(key, newTopic, queueNum, 0); + } + + public void createTopic(String key, String newTopic, int queueNum, int topicSysFlag) throws MQClientException { + this.makeSureStateOK(); + Validators.checkTopic(newTopic); + + this.mQClientFactory.getMQAdminImpl().createTopic(key, newTopic, queueNum, topicSysFlag); + } + + private void makeSureStateOK() throws MQClientException { + if (this.serviceState != ServiceState.RUNNING) { + throw new MQClientException("The producer service state not OK, " + + this.serviceState + + FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK), + null); + } + } + + public List fetchPublishMessageQueues(String topic) throws MQClientException { + this.makeSureStateOK(); + return this.mQClientFactory.getMQAdminImpl().fetchPublishMessageQueues(topic); + } + + public long searchOffset(MessageQueue mq, long timestamp) throws MQClientException { + this.makeSureStateOK(); + return this.mQClientFactory.getMQAdminImpl().searchOffset(mq, timestamp); + } + + public long maxOffset(MessageQueue mq) throws MQClientException { + this.makeSureStateOK(); + return this.mQClientFactory.getMQAdminImpl().maxOffset(mq); + } + + public long minOffset(MessageQueue mq) throws MQClientException { + this.makeSureStateOK(); + return this.mQClientFactory.getMQAdminImpl().minOffset(mq); + } + + public long earliestMsgStoreTime(MessageQueue mq) throws MQClientException { + this.makeSureStateOK(); + return this.mQClientFactory.getMQAdminImpl().earliestMsgStoreTime(mq); + } + + public MessageExt viewMessage(String msgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { + this.makeSureStateOK(); + + return this.mQClientFactory.getMQAdminImpl().viewMessage(msgId); + } + + public QueryResult queryMessage(String topic, String key, int maxNum, long begin, long end) + throws MQClientException, InterruptedException { + this.makeSureStateOK(); + return this.mQClientFactory.getMQAdminImpl().queryMessage(topic, key, maxNum, begin, end); + } + + public MessageExt queryMessageByUniqKey(String topic, String uniqKey) + throws MQClientException, InterruptedException { + this.makeSureStateOK(); + return this.mQClientFactory.getMQAdminImpl().queryMessageByUniqKey(topic, uniqKey); + } + + /** + * DEFAULT ASYNC ------------------------------------------------------- + */ + public void send(Message msg, SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException { + send(msg, sendCallback, this.defaultMQProducer.getSendMsgTimeout()); + } + + /** + * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout. + * A new one will be provided in next version + * @param msg + * @param sendCallback + * @param timeout the sendCallback will be invoked at most time + * @throws RejectedExecutionException + */ + @Deprecated + public void send(final Message msg, final SendCallback sendCallback, final long timeout) + throws MQClientException, RemotingException, InterruptedException { + try { + this.sendDefaultImpl(msg, CommunicationMode.ASYNC, sendCallback, timeout); + } catch (Exception e) { + sendCallback.onException(e); + } + } + + public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) { + return this.mqFaultStrategy.selectOneMessageQueue(tpInfo, lastBrokerName); + } + + public void updateFaultItem(final String brokerName, final long currentLatency, boolean isolation) { + this.mqFaultStrategy.updateFaultItem(brokerName, currentLatency, isolation); + } + + private SendResult sendDefaultImpl( + Message msg, + final CommunicationMode communicationMode, + final SendCallback sendCallback, + final long timeout + ) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + this.makeSureStateOK(); + Validators.checkMessage(msg, this.defaultMQProducer); + + final long invokeID = random.nextLong(); + long beginTimestampFirst = System.currentTimeMillis(); + long beginTimestampPrev = beginTimestampFirst; + long endTimestamp = beginTimestampFirst; + TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic()); + if (topicPublishInfo != null && topicPublishInfo.ok()) { + boolean callTimeout = false; + MessageQueue mq = null; + Exception exception = null; + SendResult sendResult = null; + int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1; + int times = 0; + String[] brokersSent = new String[timesTotal]; + for (; times < timesTotal; times++) { + String lastBrokerName = null == mq ? null : mq.getBrokerName(); + MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName); + if (mqSelected != null) { + mq = mqSelected; + brokersSent[times] = mq.getBrokerName(); + try { + beginTimestampPrev = System.currentTimeMillis(); + long costTime = beginTimestampPrev - beginTimestampFirst; + if (timeout < costTime) { + callTimeout = true; + break; + } + + sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime); + endTimestamp = System.currentTimeMillis(); + this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false); + switch (communicationMode) { + case ASYNC: + return null; + case ONEWAY: + return null; + case SYNC: + if (sendResult.getSendStatus() != SendStatus.SEND_OK) { + if (this.defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()) { + continue; + } + } + + return sendResult; + default: + break; + } + } catch (RemotingException e) { + endTimestamp = System.currentTimeMillis(); + this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true); + log.warn(String.format("sendKernelImpl failed, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e); + log.warn(msg.toString()); + exception = e; + continue; + } catch (MQClientException e) { + endTimestamp = System.currentTimeMillis(); + this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true); + log.warn(String.format("sendKernelImpl failed, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e); + log.warn(msg.toString()); + exception = e; + continue; + } catch (MQBrokerException e) { + endTimestamp = System.currentTimeMillis(); + this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true); + log.warn(String.format("sendKernelImpl failed, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e); + log.warn(msg.toString()); + exception = e; + switch (e.getResponseCode()) { + case ResponseCode.TOPIC_NOT_EXIST: + case ResponseCode.SERVICE_NOT_AVAILABLE: + case ResponseCode.SYSTEM_ERROR: + case ResponseCode.NO_PERMISSION: + case ResponseCode.NO_BUYER_ID: + case ResponseCode.NOT_IN_CURRENT_UNIT: + continue; + default: + if (sendResult != null) { + return sendResult; + } + + throw e; + } + } catch (InterruptedException e) { + endTimestamp = System.currentTimeMillis(); + this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false); + log.warn(String.format("sendKernelImpl failed, throw except, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e); + log.warn(msg.toString()); + + log.warn("sendKernelImpl failed", e); + log.warn(msg.toString()); + throw e; + } + } else { + break; + } + } + + if (sendResult != null) { + return sendResult; + } + + String info = String.format("Send [%d] times, still failed, cost [%d]ms, Topic: %s, BrokersSent: %s", + times, + System.currentTimeMillis() - beginTimestampFirst, + msg.getTopic(), + Arrays.toString(brokersSent)); + + info += FAQUrl.suggestTodo(FAQUrl.SEND_MSG_FAILED); + + MQClientException mqClientException = new MQClientException(info, exception); + if (callTimeout) { + throw new RemotingTooMuchRequestException("sendDefaultImpl call timeout"); + } + + if (exception instanceof MQBrokerException) { + mqClientException.setResponseCode(((MQBrokerException) exception).getResponseCode()); + } else if (exception instanceof RemotingConnectException) { + mqClientException.setResponseCode(ClientErrorCode.CONNECT_BROKER_EXCEPTION); + } else if (exception instanceof RemotingTimeoutException) { + mqClientException.setResponseCode(ClientErrorCode.ACCESS_BROKER_TIMEOUT); + } else if (exception instanceof MQClientException) { + mqClientException.setResponseCode(ClientErrorCode.BROKER_NOT_EXIST_EXCEPTION); + } + + throw mqClientException; + } + + List nsList = this.getmQClientFactory().getMQClientAPIImpl().getNameServerAddressList(); + if (null == nsList || nsList.isEmpty()) { + throw new MQClientException( + "No name server address, please set it." + FAQUrl.suggestTodo(FAQUrl.NAME_SERVER_ADDR_NOT_EXIST_URL), null).setResponseCode(ClientErrorCode.NO_NAME_SERVER_EXCEPTION); + } + + if (topicPublishInfo != null && topicPublishInfo.getTopicRouteData() != null) { + int queueNum = calculateWriteQueueNumInRouteInfo(topicPublishInfo.getTopicRouteData()); + if (queueNum <= 0) { + throw new MQClientException("No route info of this topic, " + msg.getTopic() + ", write queue num is 0, maybe consumer not online" + FAQUrl.suggestTodo(FAQUrl.NO_TOPIC_ROUTE_INFO), + null).setResponseCode(ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION); + } + } + + throw new MQClientException("No route info of this topic, " + msg.getTopic() + FAQUrl.suggestTodo(FAQUrl.NO_TOPIC_ROUTE_INFO), + null).setResponseCode(ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION); + } + + private int calculateWriteQueueNumInRouteInfo(final TopicRouteData topicRouteData) { + int totalQueueNum = 0; + if (topicRouteData.getQueueDatas() != null && topicRouteData.getQueueDatas().size() > 0) { + for (QueueData queueData : topicRouteData.getQueueDatas()) { + totalQueueNum += queueData.getWriteQueueNums(); + } + } + return totalQueueNum; + } + + private TopicPublishInfo tryToFindTopicPublishInfo(final String topic) { + TopicPublishInfo topicPublishInfo = this.topicPublishInfoTable.get(topic); + if (null == topicPublishInfo || !topicPublishInfo.ok()) { + this.topicPublishInfoTable.putIfAbsent(topic, new TopicPublishInfo()); + this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic); + topicPublishInfo = this.topicPublishInfoTable.get(topic); + } + + if (topicPublishInfo.isHaveTopicRouterInfo() || topicPublishInfo.ok()) { + return topicPublishInfo; + } else { + this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic, true, this.defaultMQProducer); + topicPublishInfo = this.topicPublishInfoTable.get(topic); + return topicPublishInfo; + } + } + + private SendResult sendKernelImpl(final Message msg, + final MessageQueue mq, + final CommunicationMode communicationMode, + final SendCallback sendCallback, + final TopicPublishInfo topicPublishInfo, + final long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + long beginStartTime = System.currentTimeMillis(); + String brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(mq.getBrokerName()); + if (null == brokerAddr) { + tryToFindTopicPublishInfo(mq.getTopic()); + brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(mq.getBrokerName()); + } + + SendMessageContext context = null; + if (brokerAddr != null) { + brokerAddr = MixAll.brokerVIPChannel(this.defaultMQProducer.isSendMessageWithVIPChannel(), brokerAddr); + + byte[] prevBody = msg.getBody(); + try { + //for MessageBatch,ID has been set in the generating process + if (!(msg instanceof MessageBatch)) { + MessageClientIDSetter.setUniqID(msg); + } + + int sysFlag = 0; + boolean msgBodyCompressed = false; + if (this.tryToCompressMessage(msg)) { + sysFlag |= MessageSysFlag.COMPRESSED_FLAG; + msgBodyCompressed = true; + } + + final String tranMsg = msg.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); + if (tranMsg != null && Boolean.parseBoolean(tranMsg)) { + sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; + } + + if (hasCheckForbiddenHook()) { + CheckForbiddenContext checkForbiddenContext = new CheckForbiddenContext(); + checkForbiddenContext.setNameSrvAddr(this.defaultMQProducer.getNamesrvAddr()); + checkForbiddenContext.setGroup(this.defaultMQProducer.getProducerGroup()); + checkForbiddenContext.setCommunicationMode(communicationMode); + checkForbiddenContext.setBrokerAddr(brokerAddr); + checkForbiddenContext.setMessage(msg); + checkForbiddenContext.setMq(mq); + checkForbiddenContext.setUnitMode(this.isUnitMode()); + this.executeCheckForbiddenHook(checkForbiddenContext); + } + + if (this.hasSendMessageHook()) { + context = new SendMessageContext(); + context.setProducer(this); + context.setProducerGroup(this.defaultMQProducer.getProducerGroup()); + context.setCommunicationMode(communicationMode); + context.setBornHost(this.defaultMQProducer.getClientIP()); + context.setBrokerAddr(brokerAddr); + context.setMessage(msg); + context.setMq(mq); + String isTrans = msg.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); + if (isTrans != null && isTrans.equals("true")) { + context.setMsgType(MessageType.Trans_Msg_Half); + } + + if (msg.getProperty("__STARTDELIVERTIME") != null || msg.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null) { + context.setMsgType(MessageType.Delay_Msg); + } + this.executeSendMessageHookBefore(context); + } + + SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); + requestHeader.setProducerGroup(this.defaultMQProducer.getProducerGroup()); + requestHeader.setTopic(msg.getTopic()); + requestHeader.setDefaultTopic(this.defaultMQProducer.getCreateTopicKey()); + requestHeader.setDefaultTopicQueueNums(this.defaultMQProducer.getDefaultTopicQueueNums()); + requestHeader.setQueueId(mq.getQueueId()); + requestHeader.setSysFlag(sysFlag); + requestHeader.setBornTimestamp(System.currentTimeMillis()); + requestHeader.setFlag(msg.getFlag()); + requestHeader.setProperties(MessageDecoder.messageProperties2String(msg.getProperties())); + requestHeader.setReconsumeTimes(0); + requestHeader.setUnitMode(this.isUnitMode()); + requestHeader.setBatch(msg instanceof MessageBatch); + if (requestHeader.getTopic().startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) { + String reconsumeTimes = MessageAccessor.getReconsumeTime(msg); + if (reconsumeTimes != null) { + requestHeader.setReconsumeTimes(Integer.valueOf(reconsumeTimes)); + MessageAccessor.clearProperty(msg, MessageConst.PROPERTY_RECONSUME_TIME); + } + + String maxReconsumeTimes = MessageAccessor.getMaxReconsumeTimes(msg); + if (maxReconsumeTimes != null) { + requestHeader.setMaxReconsumeTimes(Integer.valueOf(maxReconsumeTimes)); + MessageAccessor.clearProperty(msg, MessageConst.PROPERTY_MAX_RECONSUME_TIMES); + } + } + + SendResult sendResult = null; + switch (communicationMode) { + case ASYNC: + Message tmpMessage = msg; + if (msgBodyCompressed) { + //If msg body was compressed, msgbody should be reset using prevBody. + //Clone new message using commpressed message body and recover origin massage. + //Fix bug:https://github.com/apache/rocketmq-externals/issues/66 + tmpMessage = MessageAccessor.cloneMessage(msg); + msg.setBody(prevBody); + } + long costTimeAsync = System.currentTimeMillis() - beginStartTime; + if (timeout < costTimeAsync) { + throw new RemotingTooMuchRequestException("sendKernelImpl call timeout"); + } + sendResult = this.mQClientFactory.getMQClientAPIImpl().sendMessage( + brokerAddr, + mq.getBrokerName(), + tmpMessage, + requestHeader, + timeout - costTimeAsync, + communicationMode, + sendCallback, + topicPublishInfo, + this.mQClientFactory, + this.defaultMQProducer.getRetryTimesWhenSendAsyncFailed(), + context, + this); + break; + case ONEWAY: + case SYNC: + long costTimeSync = System.currentTimeMillis() - beginStartTime; + if (timeout < costTimeSync) { + throw new RemotingTooMuchRequestException("sendKernelImpl call timeout"); + } + sendResult = this.mQClientFactory.getMQClientAPIImpl().sendMessage( + brokerAddr, + mq.getBrokerName(), + msg, + requestHeader, + timeout - costTimeSync, + communicationMode, + context, + this); + break; + default: + assert false; + break; + } + + if (this.hasSendMessageHook()) { + context.setSendResult(sendResult); + this.executeSendMessageHookAfter(context); + } + + return sendResult; + } catch (RemotingException e) { + if (this.hasSendMessageHook()) { + context.setException(e); + this.executeSendMessageHookAfter(context); + } + throw e; + } catch (MQBrokerException e) { + if (this.hasSendMessageHook()) { + context.setException(e); + this.executeSendMessageHookAfter(context); + } + throw e; + } catch (InterruptedException e) { + if (this.hasSendMessageHook()) { + context.setException(e); + this.executeSendMessageHookAfter(context); + } + throw e; + } finally { + msg.setBody(prevBody); + } + } + + throw new MQClientException("The broker[" + mq.getBrokerName() + "] not exist", null); + } + + public MQClientInstance getmQClientFactory() { + return mQClientFactory; + } + + private boolean tryToCompressMessage(final Message msg) { + if (msg instanceof MessageBatch) { + //batch dose not support compressing right now + return false; + } + byte[] body = msg.getBody(); + if (body != null) { + if (body.length >= this.defaultMQProducer.getCompressMsgBodyOverHowmuch()) { + try { + byte[] data = UtilAll.compress(body, zipCompressLevel); + if (data != null) { + msg.setBody(data); + return true; + } + } catch (IOException e) { + log.warn("tryToCompressMessage except", e); + log.warn(msg.toString()); + } + } + } + + return false; + } + + public boolean hasCheckForbiddenHook() { + return !checkForbiddenHookList.isEmpty(); + } + + public void executeCheckForbiddenHook(final CheckForbiddenContext context) throws MQClientException { + if (hasCheckForbiddenHook()) { + for (CheckForbiddenHook hook : checkForbiddenHookList) { + hook.checkForbidden(context); + } + } + } + + public boolean hasSendMessageHook() { + return !this.sendMessageHookList.isEmpty(); + } + + public void executeSendMessageHookBefore(final SendMessageContext context) { + if (!this.sendMessageHookList.isEmpty()) { + for (SendMessageHook hook : this.sendMessageHookList) { + try { + hook.sendMessageBefore(context); + } catch (Throwable e) { + log.warn("failed to executeSendMessageHookBefore", e); + } + } + } + } + + public void executeSendMessageHookAfter(final SendMessageContext context) { + if (!this.sendMessageHookList.isEmpty()) { + for (SendMessageHook hook : this.sendMessageHookList) { + try { + hook.sendMessageAfter(context); + } catch (Throwable e) { + log.warn("failed to executeSendMessageHookAfter", e); + } + } + } + } + + /** + * DEFAULT ONEWAY ------------------------------------------------------- + */ + public void sendOneway(Message msg) throws MQClientException, RemotingException, InterruptedException { + try { + this.sendDefaultImpl(msg, CommunicationMode.ONEWAY, null, this.defaultMQProducer.getSendMsgTimeout()); + } catch (MQBrokerException e) { + throw new MQClientException("unknown except", e); + } + } + + /** + * KERNEL SYNC ------------------------------------------------------- + */ + public SendResult send(Message msg, MessageQueue mq) + throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + return send(msg, mq, this.defaultMQProducer.getSendMsgTimeout()); + } + + public SendResult send(Message msg, MessageQueue mq, long timeout) + throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + long beginStartTime = System.currentTimeMillis(); + this.makeSureStateOK(); + Validators.checkMessage(msg, this.defaultMQProducer); + + if (!msg.getTopic().equals(mq.getTopic())) { + throw new MQClientException("message's topic not equal mq's topic", null); + } + + long costTime = System.currentTimeMillis() - beginStartTime; + if (timeout < costTime) { + throw new RemotingTooMuchRequestException("call timeout"); + } + + return this.sendKernelImpl(msg, mq, CommunicationMode.SYNC, null, null, timeout); + } + + /** + * KERNEL ASYNC ------------------------------------------------------- + */ + public void send(Message msg, MessageQueue mq, SendCallback sendCallback) + throws MQClientException, RemotingException, InterruptedException { + send(msg, mq, sendCallback, this.defaultMQProducer.getSendMsgTimeout()); + } + + /** + * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout. + * A new one will be provided in next version + * @param msg + * @param mq + * @param sendCallback + * @param timeout the sendCallback will be invoked at most time + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ + @Deprecated + public void send(final Message msg, final MessageQueue mq, final SendCallback sendCallback, final long timeout) + throws MQClientException, RemotingException, InterruptedException { + final long beginStartTime = System.currentTimeMillis(); + this.makeSureStateOK(); + Validators.checkMessage(msg, this.defaultMQProducer); + + if (!msg.getTopic().equals(mq.getTopic())) { + throw new MQClientException("message's topic not equal mq's topic", null); + } + long costTime = System.currentTimeMillis() - beginStartTime; + if (timeout > costTime) { + try { + this.sendKernelImpl(msg, mq, CommunicationMode.ASYNC, sendCallback, null, timeout - costTime); + } catch (MQBrokerException e) { + throw new MQClientException("unknown exception", e); + } + } else { + sendCallback.onException(new RemotingTooMuchRequestException("call timeout")); + } + } + + /** + * KERNEL ONEWAY ------------------------------------------------------- + */ + public void sendOneway(Message msg, MessageQueue mq) throws MQClientException, RemotingException, InterruptedException { + this.makeSureStateOK(); + Validators.checkMessage(msg, this.defaultMQProducer); + + try { + this.sendKernelImpl(msg, mq, CommunicationMode.ONEWAY, null, null, this.defaultMQProducer.getSendMsgTimeout()); + } catch (MQBrokerException e) { + throw new MQClientException("unknown except", e); + } + } + + /** + * SELECT SYNC ------------------------------------------------------- + */ + public SendResult send(Message msg, MessageQueueSelector selector, Object arg) + throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + return send(msg, selector, arg, this.defaultMQProducer.getSendMsgTimeout()); + } + + public SendResult send(Message msg, MessageQueueSelector selector, Object arg, long timeout) + throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + return this.sendSelectImpl(msg, selector, arg, CommunicationMode.SYNC, null, timeout); + } + + private SendResult sendSelectImpl( + Message msg, + MessageQueueSelector selector, + Object arg, + final CommunicationMode communicationMode, + final SendCallback sendCallback, final long timeout + ) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + long beginStartTime = System.currentTimeMillis(); + this.makeSureStateOK(); + Validators.checkMessage(msg, this.defaultMQProducer); + + TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic()); + if (topicPublishInfo != null && topicPublishInfo.ok()) { + MessageQueue mq = null; + try { + mq = selector.select(topicPublishInfo.getMessageQueueList(), msg, arg); + } catch (Throwable e) { + throw new MQClientException("select message queue throwed except.", e); + } + + long costTime = System.currentTimeMillis() - beginStartTime; + if (timeout < costTime) { + throw new RemotingTooMuchRequestException("sendSelectImpl call timeout"); + } + if (mq != null) { + return this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime); + } else { + throw new MQClientException("select message queue return null.", null); + } + } + + if (topicPublishInfo != null && topicPublishInfo.getTopicRouteData() != null) { + int queueNum = calculateWriteQueueNumInRouteInfo(topicPublishInfo.getTopicRouteData()); + if (queueNum <= 0) { + throw new MQClientException("No route info of this topic, " + msg.getTopic() + ", write queue num is 0, maybe consumer not online" + FAQUrl.suggestTodo(FAQUrl.NO_TOPIC_ROUTE_INFO), + null).setResponseCode(ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION); + } + } + + throw new MQClientException("No route info for this topic, " + msg.getTopic(), null); + } + + /** + * SELECT ASYNC ------------------------------------------------------- + */ + public void send(Message msg, MessageQueueSelector selector, Object arg, SendCallback sendCallback) + throws MQClientException, RemotingException, InterruptedException { + send(msg, selector, arg, sendCallback, this.defaultMQProducer.getSendMsgTimeout()); + } + + /** + * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout. + * A new one will be provided in next version + * @param msg + * @param selector + * @param arg + * @param sendCallback + * @param timeout the sendCallback will be invoked at most time + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ + @Deprecated + public void send(final Message msg, final MessageQueueSelector selector, final Object arg, final SendCallback sendCallback, final long timeout) + throws MQClientException, RemotingException, InterruptedException { + try { + try { + this.sendSelectImpl(msg, selector, arg, CommunicationMode.ASYNC, sendCallback, timeout); + } catch (MQBrokerException e) { + throw new MQClientException("unknownn except", e); + } + } catch (Exception ex) { + sendCallback.onException(ex); + } + } + + /** + * SELECT ONEWAY ------------------------------------------------------- + */ + public void sendOneway(Message msg, MessageQueueSelector selector, Object arg) + throws MQClientException, RemotingException, InterruptedException { + try { + this.sendSelectImpl(msg, selector, arg, CommunicationMode.ONEWAY, null, this.defaultMQProducer.getSendMsgTimeout()); + } catch (MQBrokerException e) { + throw new MQClientException("unknown except", e); + } + } + + public TransactionSendResult sendMessageInTransaction(final Message msg, final TransactionListener tranExecuter, final Object arg) + throws MQClientException { + if (null == tranExecuter) { + throw new MQClientException("tranExecutor is null", null); + } + Validators.checkMessage(msg, this.defaultMQProducer); + + SendResult sendResult = null; + MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); + MessageAccessor.putProperty(msg, MessageConst.PROPERTY_PRODUCER_GROUP, this.defaultMQProducer.getProducerGroup()); + try { + sendResult = this.send(msg); + } catch (Exception e) { + throw new MQClientException("send message Exception", e); + } + + LocalTransactionState localTransactionState = LocalTransactionState.UNKNOW; + Throwable localException = null; + switch (sendResult.getSendStatus()) { + case SEND_OK: { + try { + if (sendResult.getTransactionId() != null) { + msg.putUserProperty("__transactionId__", sendResult.getTransactionId()); + } + String transactionId = msg.getProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); + if (null != transactionId && !"".equals(transactionId)) { + msg.setTransactionId(transactionId); + } + localTransactionState = tranExecuter.executeLocalTransaction(msg, arg); + if (null == localTransactionState) { + localTransactionState = LocalTransactionState.UNKNOW; + } + + if (localTransactionState != LocalTransactionState.COMMIT_MESSAGE) { + log.info("executeLocalTransactionBranch return {}", localTransactionState); + log.info(msg.toString()); + } + } catch (Throwable e) { + log.info("executeLocalTransactionBranch failed", e); + log.info(msg.toString()); + localException = e; + } + } + break; + case FLUSH_DISK_TIMEOUT: + case FLUSH_SLAVE_TIMEOUT: + case SLAVE_NOT_AVAILABLE: + localTransactionState = LocalTransactionState.ROLLBACK_MESSAGE; + break; + default: + break; + } + + try { + this.endTransaction(sendResult, localTransactionState, localException); + } catch (Exception e) { + log.warn("local transaction execute " + localTransactionState + ", but end broker transaction failed", e); + } + + TransactionSendResult transactionSendResult = new TransactionSendResult(); + transactionSendResult.setSendStatus(sendResult.getSendStatus()); + transactionSendResult.setMessageQueue(sendResult.getMessageQueue()); + transactionSendResult.setMsgId(sendResult.getMsgId()); + transactionSendResult.setQueueOffset(sendResult.getQueueOffset()); + transactionSendResult.setTransactionId(sendResult.getTransactionId()); + transactionSendResult.setLocalTransactionState(localTransactionState); + return transactionSendResult; + } + + /** + * DEFAULT SYNC ------------------------------------------------------- + */ + public SendResult send(Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + return send(msg, this.defaultMQProducer.getSendMsgTimeout()); + } + + public void endTransaction( + final SendResult sendResult, + final LocalTransactionState localTransactionState, + final Throwable localException) throws RemotingException, MQBrokerException, InterruptedException, UnknownHostException { + final MessageId id; + if (sendResult.getOffsetMsgId() != null) { + id = MessageDecoder.decodeMessageId(sendResult.getOffsetMsgId()); + } else { + id = MessageDecoder.decodeMessageId(sendResult.getMsgId()); + } + String transactionId = sendResult.getTransactionId(); + final String brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(sendResult.getMessageQueue().getBrokerName()); + EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader(); + requestHeader.setTransactionId(transactionId); + requestHeader.setCommitLogOffset(id.getOffset()); + switch (localTransactionState) { + case COMMIT_MESSAGE: + requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_COMMIT_TYPE); + break; + case ROLLBACK_MESSAGE: + requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_ROLLBACK_TYPE); + break; + case UNKNOW: + requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_NOT_TYPE); + break; + default: + break; + } + + requestHeader.setProducerGroup(this.defaultMQProducer.getProducerGroup()); + requestHeader.setTranStateTableOffset(sendResult.getQueueOffset()); + requestHeader.setMsgId(sendResult.getMsgId()); + String remark = localException != null ? ("executeLocalTransactionBranch failed: " + localException.toString()) : null; + this.mQClientFactory.getMQClientAPIImpl().endTransactionOneway(brokerAddr, requestHeader, remark, + this.defaultMQProducer.getSendMsgTimeout()); + } + + public void setCallbackExecutor(final ExecutorService callbackExecutor) { + this.mQClientFactory.getMQClientAPIImpl().getRemotingClient().setCallbackExecutor(callbackExecutor); + } + + public SendResult send(Message msg, long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + return this.sendDefaultImpl(msg, CommunicationMode.SYNC, null, timeout); + } + + public ConcurrentMap getTopicPublishInfoTable() { + return topicPublishInfoTable; + } + + public int getZipCompressLevel() { + return zipCompressLevel; + } + + public void setZipCompressLevel(int zipCompressLevel) { + this.zipCompressLevel = zipCompressLevel; + } + + public ServiceState getServiceState() { + return serviceState; + } + + public void setServiceState(ServiceState serviceState) { + this.serviceState = serviceState; + } + + public long[] getNotAvailableDuration() { + return this.mqFaultStrategy.getNotAvailableDuration(); + } + + public void setNotAvailableDuration(final long[] notAvailableDuration) { + this.mqFaultStrategy.setNotAvailableDuration(notAvailableDuration); + } + + public long[] getLatencyMax() { + return this.mqFaultStrategy.getLatencyMax(); + } + + public void setLatencyMax(final long[] latencyMax) { + this.mqFaultStrategy.setLatencyMax(latencyMax); + } + + public boolean isSendLatencyFaultEnable() { + return this.mqFaultStrategy.isSendLatencyFaultEnable(); + } + + public void setSendLatencyFaultEnable(final boolean sendLatencyFaultEnable) { + this.mqFaultStrategy.setSendLatencyFaultEnable(sendLatencyFaultEnable); + } +} diff --git a/eventmesh-emesher/src/main/java/org/apache/rocketmq/common/ServiceThread.java b/eventmesh-emesher/src/main/java/org/apache/rocketmq/common/ServiceThread.java new file mode 100644 index 0000000000..e5890a9f06 --- /dev/null +++ b/eventmesh-emesher/src/main/java/org/apache/rocketmq/common/ServiceThread.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.common; + +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +public abstract class ServiceThread implements Runnable { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME); + private static final long JOIN_TIME = 90 * 1000; + + protected final Thread thread; + protected final CountDownLatch2 waitPoint = new CountDownLatch2(1); + protected volatile AtomicBoolean hasNotified = new AtomicBoolean(false); + protected volatile boolean stopped = false; + private final boolean access; + + public ServiceThread() { + this.thread = new Thread(this, this.getServiceName()); + this.access = false; + } + + public ServiceThread(boolean access) { + if (!access) throw new UnsupportedOperationException("ServiceThread.access has to be true."); + this.thread = null; + this.access = access; + } + + public abstract String getServiceName(); + + public void start() { + if (access) { + return; + } + this.thread.start(); + } + + public void shutdown() { + this.shutdown(false); + } + + public void shutdown(final boolean interrupt) { + this.stopped = true; + log.info("shutdown thread " + this.getServiceName() + " interrupt " + interrupt); + + if (hasNotified.compareAndSet(false, true)) { + waitPoint.countDown(); // notify + } + + try { + if (!access && interrupt) { + this.thread.interrupt(); + } + + long beginTime = System.currentTimeMillis(); + if (!access && !this.thread.isDaemon()) { + this.thread.join(this.getJointime()); + } + long eclipseTime = System.currentTimeMillis() - beginTime; + log.info("join thread " + this.getServiceName() + " eclipse time(ms) " + eclipseTime + " " + + this.getJointime()); + } catch (InterruptedException e) { + log.error("Interrupted", e); + } + } + + public long getJointime() { + return JOIN_TIME; + } + + public void stop() { + this.stop(false); + } + + public void stop(final boolean interrupt) { + this.stopped = true; + log.info("stop thread " + this.getServiceName() + " interrupt " + interrupt); + + if (hasNotified.compareAndSet(false, true)) { + waitPoint.countDown(); // notify + } + + if (!access && interrupt) { + this.thread.interrupt(); + } + } + + public void makeStop() { + this.stopped = true; + log.info("makestop thread " + this.getServiceName()); + } + + public void wakeup() { + if (hasNotified.compareAndSet(false, true)) { + waitPoint.countDown(); // notify + } + } + + protected void waitForRunning(long interval) { + if (hasNotified.compareAndSet(true, false)) { + this.onWaitEnd(); + return; + } + + //entry to wait + waitPoint.reset(); + + try { + waitPoint.await(interval, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + log.error("Interrupted", e); + } finally { + hasNotified.set(false); + this.onWaitEnd(); + } + } + + protected void onWaitEnd() { + } + + public boolean isStopped() { + return stopped; + } +} diff --git a/eventmesh-emesher/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java b/eventmesh-emesher/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java new file mode 100644 index 0000000000..00168d6a02 --- /dev/null +++ b/eventmesh-emesher/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java @@ -0,0 +1,700 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.remoting.netty; + +import cn.webank.emesher.threads.ThreadPoolHelper; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelPromise; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; +import io.netty.handler.timeout.IdleStateHandler; +import io.netty.util.concurrent.DefaultEventExecutorGroup; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.remoting.ChannelEventListener; +import org.apache.rocketmq.remoting.InvokeCallback; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.RemotingClient; +import org.apache.rocketmq.remoting.common.Pair; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.apache.rocketmq.remoting.exception.RemotingConnectException; +import org.apache.rocketmq.remoting.exception.RemotingSendRequestException; +import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; +import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +import java.io.IOException; +import java.net.SocketAddress; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class NettyRemotingClient extends NettyRemotingAbstract implements RemotingClient { + private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING); + + private static final long LOCK_TIMEOUT_MILLIS = 3000; + + private final NettyClientConfig nettyClientConfig; + private final Bootstrap bootstrap = new Bootstrap(); + private final EventLoopGroup eventLoopGroupWorker; + private final Lock lockChannelTables = new ReentrantLock(); + private final ConcurrentMap channelTables = new ConcurrentHashMap(); + + private final ScheduledExecutorService timer = ThreadPoolHelper.getClientHouseKeepingService(); + + private final AtomicReference> namesrvAddrList = new AtomicReference>(); + private final AtomicReference namesrvAddrChoosed = new AtomicReference(); + private final AtomicInteger namesrvIndex = new AtomicInteger(initValueIndex()); + private final Lock lockNamesrvChannel = new ReentrantLock(); + + private final ExecutorService publicExecutor; + + /** + * Invoke the callback methods in this executor when process response. + */ + private ExecutorService callbackExecutor; + private final ChannelEventListener channelEventListener; + private DefaultEventExecutorGroup defaultEventExecutorGroup; + private RPCHook rpcHook; + + public NettyRemotingClient(final NettyClientConfig nettyClientConfig) { + this(nettyClientConfig, null); + } + + public NettyRemotingClient(final NettyClientConfig nettyClientConfig, + final ChannelEventListener channelEventListener) { + super(nettyClientConfig.getClientOnewaySemaphoreValue(), nettyClientConfig.getClientAsyncSemaphoreValue()); + this.nettyClientConfig = nettyClientConfig; + this.channelEventListener = channelEventListener; + + int publicThreadNums = nettyClientConfig.getClientCallbackExecutorThreads(); + if (publicThreadNums <= 0) { + publicThreadNums = 4; + } + + this.publicExecutor = ThreadPoolHelper.getNettyClientPublicExecutor(); + + this.eventLoopGroupWorker = ThreadPoolHelper.getNettyClientSelectors(); + + if (nettyClientConfig.isUseTLS()) { + try { + sslContext = TlsHelper.buildSslContext(true); + log.info("SSL enabled for client"); + } catch (IOException e) { + log.error("Failed to create SSLContext", e); + } catch (CertificateException e) { + log.error("Failed to create SSLContext", e); + throw new RuntimeException("Failed to create SSLContext", e); + } + } + } + + private static int initValueIndex() { + SecureRandom r = new SecureRandom(); + + return Math.abs(r.nextInt() % 999) % 999; + } + + @Override + public void start() { + this.defaultEventExecutorGroup = ThreadPoolHelper.getNettyClientWorkerThreads(); +// this.defaultEventExecutorGroup = new DefaultEventExecutorGroup( +// nettyClientConfig.getClientWorkerThreads(), +// new ThreadFactory() { +// +// private AtomicInteger threadIndex = new AtomicInteger(0); +// +// @Override +// public Thread newThread(Runnable r) { +// return new Thread(r, "NettyClientWorkerThread_" + this.threadIndex.incrementAndGet()); +// } +// }); + + Bootstrap handler = this.bootstrap.group(this.eventLoopGroupWorker).channel(NioSocketChannel.class) + .option(ChannelOption.TCP_NODELAY, true) + .option(ChannelOption.SO_KEEPALIVE, false) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, nettyClientConfig.getConnectTimeoutMillis()) + .option(ChannelOption.SO_SNDBUF, nettyClientConfig.getClientSocketSndBufSize()) + .option(ChannelOption.SO_RCVBUF, nettyClientConfig.getClientSocketRcvBufSize()) + .handler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + if (nettyClientConfig.isUseTLS()) { + if (null != sslContext) { + pipeline.addFirst(defaultEventExecutorGroup, "sslHandler", sslContext.newHandler(ch.alloc())); + log.info("Prepend SSL handler"); + } else { + log.warn("Connections are insecure as SSLContext is null!"); + } + } + pipeline.addLast( + defaultEventExecutorGroup, + new NettyEncoder(), + new NettyDecoder(), + new IdleStateHandler(nettyClientConfig.getClientChannelMaxIdleTimeSeconds(), nettyClientConfig.getClientChannelMaxIdleTimeSeconds(), 0), + new NettyConnectManageHandler(), + new NettyClientHandler()); + } + }); + + this.timer.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + try { + NettyRemotingClient.this.scanResponseTable(); + } catch (Throwable e) { + log.error("scanResponseTable exception", e); + } + } + }, 1000 * 3, 1000, TimeUnit.MILLISECONDS); + + if (this.channelEventListener != null) { + this.nettyEventExecutor.start(); + } + } + + @Override + public void shutdown() { + try { + this.timer.shutdown(); + + for (ChannelWrapper cw : this.channelTables.values()) { + this.closeChannel(null, cw.getChannel()); + } + + this.channelTables.clear(); + + this.eventLoopGroupWorker.shutdownGracefully(); + + if (this.nettyEventExecutor != null) { + this.nettyEventExecutor.shutdown(); + } + + if (this.defaultEventExecutorGroup != null) { + this.defaultEventExecutorGroup.shutdownGracefully(); + } + } catch (Exception e) { + log.error("NettyRemotingClient shutdown exception, ", e); + } + + if (this.publicExecutor != null) { + try { + this.publicExecutor.shutdown(); + } catch (Exception e) { + log.error("NettyRemotingServer shutdown exception, ", e); + } + } + } + + public void closeChannel(final String addr, final Channel channel) { + if (null == channel) + return; + + final String addrRemote = null == addr ? RemotingHelper.parseChannelRemoteAddr(channel) : addr; + + try { + if (this.lockChannelTables.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) { + try { + boolean removeItemFromTable = true; + final ChannelWrapper prevCW = this.channelTables.get(addrRemote); + + log.info("closeChannel: begin close the channel[{}] Found: {}", addrRemote, prevCW != null); + + if (null == prevCW) { + log.info("closeChannel: the channel[{}] has been removed from the channel table before", addrRemote); + removeItemFromTable = false; + } else if (prevCW.getChannel() != channel) { + log.info("closeChannel: the channel[{}] has been closed before, and has been created again, nothing to do.", + addrRemote); + removeItemFromTable = false; + } + + if (removeItemFromTable) { + this.channelTables.remove(addrRemote); + log.info("closeChannel: the channel[{}] was removed from channel table", addrRemote); + } + + RemotingUtil.closeChannel(channel); + } catch (Exception e) { + log.error("closeChannel: close the channel exception", e); + } finally { + this.lockChannelTables.unlock(); + } + } else { + log.warn("closeChannel: try to lock channel table, but timeout, {}ms", LOCK_TIMEOUT_MILLIS); + } + } catch (InterruptedException e) { + log.error("closeChannel exception", e); + } + } + + @Override + public void registerRPCHook(RPCHook rpcHook) { + this.rpcHook = rpcHook; + } + + public void closeChannel(final Channel channel) { + if (null == channel) + return; + + try { + if (this.lockChannelTables.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) { + try { + boolean removeItemFromTable = true; + ChannelWrapper prevCW = null; + String addrRemote = null; + for (Map.Entry entry : channelTables.entrySet()) { + String key = entry.getKey(); + ChannelWrapper prev = entry.getValue(); + if (prev.getChannel() != null) { + if (prev.getChannel() == channel) { + prevCW = prev; + addrRemote = key; + break; + } + } + } + + if (null == prevCW) { + log.info("eventCloseChannel: the channel[{}] has been removed from the channel table before", addrRemote); + removeItemFromTable = false; + } + + if (removeItemFromTable) { + this.channelTables.remove(addrRemote); + log.info("closeChannel: the channel[{}] was removed from channel table", addrRemote); + RemotingUtil.closeChannel(channel); + } + } catch (Exception e) { + log.error("closeChannel: close the channel exception", e); + } finally { + this.lockChannelTables.unlock(); + } + } else { + log.warn("closeChannel: try to lock channel table, but timeout, {}ms", LOCK_TIMEOUT_MILLIS); + } + } catch (InterruptedException e) { + log.error("closeChannel exception", e); + } + } + + @Override + public void updateNameServerAddressList(List addrs) { + List old = this.namesrvAddrList.get(); + boolean update = false; + + if (!addrs.isEmpty()) { + if (null == old) { + update = true; + } else if (addrs.size() != old.size()) { + update = true; + } else { + for (int i = 0; i < addrs.size() && !update; i++) { + if (!old.contains(addrs.get(i))) { + update = true; + } + } + } + + if (update) { + Collections.shuffle(addrs); + log.info("name server address updated. NEW : {} , OLD: {}", addrs, old); + this.namesrvAddrList.set(addrs); + } + } + } + + @Override + public RemotingCommand invokeSync(String addr, final RemotingCommand request, long timeoutMillis) + throws InterruptedException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException { + long beginStartTime = System.currentTimeMillis(); + final Channel channel = this.getAndCreateChannel(addr); + if (channel != null && channel.isActive()) { + try { + if (this.rpcHook != null) { + this.rpcHook.doBeforeRequest(addr, request); + } + long costTime = System.currentTimeMillis() - beginStartTime; + if (timeoutMillis < costTime) { + throw new RemotingTimeoutException("invokeSync call timeout"); + } + RemotingCommand response = this.invokeSyncImpl(channel, request, timeoutMillis - costTime); + if (this.rpcHook != null) { + this.rpcHook.doAfterResponse(RemotingHelper.parseChannelRemoteAddr(channel), request, response); + } + return response; + } catch (RemotingSendRequestException e) { + log.warn("invokeSync: send request exception, so close the channel[{}]", addr); + this.closeChannel(addr, channel); + throw e; + } catch (RemotingTimeoutException e) { + if (nettyClientConfig.isClientCloseSocketIfTimeout()) { + this.closeChannel(addr, channel); + log.warn("invokeSync: close socket because of timeout, {}ms, {}", timeoutMillis, addr); + } + log.warn("invokeSync: wait response timeout exception, the channel[{}]", addr); + throw e; + } + } else { + this.closeChannel(addr, channel); + throw new RemotingConnectException(addr); + } + } + + private Channel getAndCreateChannel(final String addr) throws InterruptedException { + if (null == addr) { + return getAndCreateNameserverChannel(); + } + + ChannelWrapper cw = this.channelTables.get(addr); + if (cw != null && cw.isOK()) { + return cw.getChannel(); + } + + return this.createChannel(addr); + } + + private Channel getAndCreateNameserverChannel() throws InterruptedException { + String addr = this.namesrvAddrChoosed.get(); + if (addr != null) { + ChannelWrapper cw = this.channelTables.get(addr); + if (cw != null && cw.isOK()) { + return cw.getChannel(); + } + } + + final List addrList = this.namesrvAddrList.get(); + if (this.lockNamesrvChannel.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) { + try { + addr = this.namesrvAddrChoosed.get(); + if (addr != null) { + ChannelWrapper cw = this.channelTables.get(addr); + if (cw != null && cw.isOK()) { + return cw.getChannel(); + } + } + + if (addrList != null && !addrList.isEmpty()) { + for (int i = 0; i < addrList.size(); i++) { + int index = this.namesrvIndex.incrementAndGet(); + index = Math.abs(index); + index = index % addrList.size(); + String newAddr = addrList.get(index); + + this.namesrvAddrChoosed.set(newAddr); + log.info("new name server is chosen. OLD: {} , NEW: {}. namesrvIndex = {}", addr, newAddr, namesrvIndex); + Channel channelNew = this.createChannel(newAddr); + if (channelNew != null) { + return channelNew; + } + } + } + } catch (Exception e) { + log.error("getAndCreateNameserverChannel: create name server channel exception", e); + } finally { + this.lockNamesrvChannel.unlock(); + } + } else { + log.warn("getAndCreateNameserverChannel: try to lock name server, but timeout, {}ms", LOCK_TIMEOUT_MILLIS); + } + + return null; + } + + private Channel createChannel(final String addr) throws InterruptedException { + try { + SecureRandom random = new SecureRandom(); + int sleepMills = random.nextInt(10); + //sleep 0-10 ms randomly + Thread.sleep(sleepMills); + } catch (Exception ignored) { + } + + ChannelWrapper cw = this.channelTables.get(addr); + if (cw != null && cw.isOK()) { + return cw.getChannel(); + } + + if (this.lockChannelTables.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) { + try { + boolean createNewConnection; + cw = this.channelTables.get(addr); + if (cw != null) { + + if (cw.isOK()) { + return cw.getChannel(); + } else if (!cw.getChannelFuture().isDone()) { + createNewConnection = false; + } else { + this.channelTables.remove(addr); + createNewConnection = true; + } + } else { + createNewConnection = true; + } + + if (createNewConnection) { + ChannelFuture channelFuture = this.bootstrap.connect(RemotingHelper.string2SocketAddress(addr)); + log.info("createChannel: begin to connect remote host[{}] asynchronously", addr); + cw = new ChannelWrapper(channelFuture); + this.channelTables.put(addr, cw); + } + } catch (Exception e) { + log.error("createChannel: create channel exception", e); + } finally { + this.lockChannelTables.unlock(); + } + } else { + log.warn("createChannel: try to lock channel table, but timeout, {}ms", LOCK_TIMEOUT_MILLIS); + } + + if (cw != null) { + ChannelFuture channelFuture = cw.getChannelFuture(); + if (channelFuture.awaitUninterruptibly(this.nettyClientConfig.getConnectTimeoutMillis())) { + if (cw.isOK()) { + log.info("createChannel: connect remote host[{}] success, {}", addr, channelFuture.toString()); + return cw.getChannel(); + } else { + log.warn("createChannel: connect remote host[" + addr + "] failed, " + channelFuture.toString() + ", " + channelFuture.cause()); + } + } else { + log.warn("createChannel: connect remote host[{}] timeout {}ms, {}", addr, this.nettyClientConfig.getConnectTimeoutMillis(), + channelFuture.toString()); + } + } + + return null; + } + + @Override + public void invokeAsync(String addr, RemotingCommand request, long timeoutMillis, InvokeCallback invokeCallback) + throws InterruptedException, RemotingConnectException, RemotingTooMuchRequestException, RemotingTimeoutException, + RemotingSendRequestException { + long beginStartTime = System.currentTimeMillis(); + final Channel channel = this.getAndCreateChannel(addr); + if (channel != null && channel.isActive()) { + try { + if (this.rpcHook != null) { + this.rpcHook.doBeforeRequest(addr, request); + } + long costTime = System.currentTimeMillis() - beginStartTime; + if (timeoutMillis < costTime) { + throw new RemotingTooMuchRequestException("invokeAsync call timeout"); + } + this.invokeAsyncImpl(channel, request, timeoutMillis - costTime, invokeCallback); + } catch (RemotingSendRequestException e) { + log.warn("invokeAsync: send request exception, so close the channel[{}]", addr); + this.closeChannel(addr, channel); + throw e; + } + } else { + this.closeChannel(addr, channel); + throw new RemotingConnectException(addr); + } + } + + @Override + public void invokeOneway(String addr, RemotingCommand request, long timeoutMillis) throws InterruptedException, + RemotingConnectException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException { + final Channel channel = this.getAndCreateChannel(addr); + if (channel != null && channel.isActive()) { + try { + if (this.rpcHook != null) { + this.rpcHook.doBeforeRequest(addr, request); + } + this.invokeOnewayImpl(channel, request, timeoutMillis); + } catch (RemotingSendRequestException e) { + log.warn("invokeOneway: send request exception, so close the channel[{}]", addr); + this.closeChannel(addr, channel); + throw e; + } + } else { + this.closeChannel(addr, channel); + throw new RemotingConnectException(addr); + } + } + + @Override + public void registerProcessor(int requestCode, NettyRequestProcessor processor, ExecutorService executor) { + ExecutorService executorThis = executor; + if (null == executor) { + executorThis = this.publicExecutor; + } + + Pair pair = new Pair(processor, executorThis); + this.processorTable.put(requestCode, pair); + } + + @Override + public boolean isChannelWritable(String addr) { + ChannelWrapper cw = this.channelTables.get(addr); + if (cw != null && cw.isOK()) { + return cw.isWritable(); + } + return true; + } + + @Override + public List getNameServerAddressList() { + return this.namesrvAddrList.get(); + } + + @Override + public ChannelEventListener getChannelEventListener() { + return channelEventListener; + } + + @Override + public RPCHook getRPCHook() { + return this.rpcHook; + } + + @Override + public ExecutorService getCallbackExecutor() { + return callbackExecutor != null ? callbackExecutor : publicExecutor; + } + + @Override + public void setCallbackExecutor(final ExecutorService callbackExecutor) { + this.callbackExecutor = callbackExecutor; + } + + static class ChannelWrapper { + private final ChannelFuture channelFuture; + + public ChannelWrapper(ChannelFuture channelFuture) { + this.channelFuture = channelFuture; + } + + public boolean isOK() { + return this.channelFuture.channel() != null && this.channelFuture.channel().isActive(); + } + + public boolean isWritable() { + return this.channelFuture.channel().isWritable(); + } + + private Channel getChannel() { + return this.channelFuture.channel(); + } + + public ChannelFuture getChannelFuture() { + return channelFuture; + } + } + + class NettyClientHandler extends SimpleChannelInboundHandler { + + @Override + protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception { + processMessageReceived(ctx, msg); + } + } + + class NettyConnectManageHandler extends ChannelDuplexHandler { + @Override + public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, + ChannelPromise promise) throws Exception { + final String local = localAddress == null ? "UNKNOWN" : RemotingHelper.parseSocketAddressAddr(localAddress); + final String remote = remoteAddress == null ? "UNKNOWN" : RemotingHelper.parseSocketAddressAddr(remoteAddress); + log.info("NETTY CLIENT PIPELINE: CONNECT {} => {}", local, remote); + + super.connect(ctx, remoteAddress, localAddress, promise); + + if (NettyRemotingClient.this.channelEventListener != null) { + NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remote, ctx.channel())); + } + } + + @Override + public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.info("NETTY CLIENT PIPELINE: DISCONNECT {}", remoteAddress); + closeChannel(ctx.channel()); + super.disconnect(ctx, promise); + + if (NettyRemotingClient.this.channelEventListener != null) { + NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel())); + } + } + + @Override + public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.info("NETTY CLIENT PIPELINE: CLOSE {}", remoteAddress); + closeChannel(ctx.channel()); + super.close(ctx, promise); + NettyRemotingClient.this.failFast(ctx.channel()); + if (NettyRemotingClient.this.channelEventListener != null) { + NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel())); + } + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + if (event.state().equals(IdleState.ALL_IDLE) || event.state().equals(IdleState.WRITER_IDLE) || event.state().equals(IdleState.READER_IDLE)) { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.warn("NETTY CLIENT PIPELINE: IDLE [{}]", remoteAddress); + closeChannel(ctx.channel()); + if (NettyRemotingClient.this.channelEventListener != null) { + NettyRemotingClient.this + .putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress, ctx.channel())); + } + } + } + + ctx.fireUserEventTriggered(evt); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.warn("NETTY CLIENT PIPELINE: exceptCaught {}", remoteAddress); + log.warn("NETTY CLIENT PIPELINE: exceptCaught {}", cause); + closeChannel(ctx.channel()); + if (NettyRemotingClient.this.channelEventListener != null) { + NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress, ctx.channel())); + } + } + } +} diff --git a/eventmesh-emesher/src/main/resources/log4j2.xml b/eventmesh-emesher/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..9e60f7e2fc --- /dev/null +++ b/eventmesh-emesher/src/main/resources/log4j2.xml @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eventmesh-examples/bin/http_pub.sh b/eventmesh-examples/bin/http_pub.sh new file mode 100644 index 0000000000..3fdb0b0f65 --- /dev/null +++ b/eventmesh-examples/bin/http_pub.sh @@ -0,0 +1,135 @@ +#!/bin/sh + + +# Copyright (C) @2017 Webank Group Holding Limited +# +# Licensed 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. +# + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== +set -e +#服务器配置可能不一致,增加这些配置避免乱码问题 +export LANG=en_US.UTF-8 +export LC_CTYPE=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 + +TMP_JAVA_HOME="/nemo/jdk1.8.0_152" + +#detect operating system. +OS=$(uname -o) + +function is_java8 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' ]] || return 2 + return 0 +} + + +function get_pid { + local ppid="" + if [ -f ${DEMO_HOME}/bin/pid_http_pub.file ]; then + ppid=$(cat ${DEMO_HOME}/bin/pid_http_pub.file) + else + if [[ $OS =~ Msys ]]; then + # 在Msys上存在可能无法kill识别出的进程的BUG + ppid=`jps -v | grep -i "com.webank.eventmesh.http.demo.AsyncPublishInstance" | grep java | grep -v grep | awk -F ' ' {'print $1'}` + elif [[ $OS =~ Darwin ]]; then + # 已知问题:grep java 可能无法精确识别java进程 + ppid=$(/bin/ps -o user,pid,command | grep "java" | grep -i "com.webank.eventmesh.http.demo.AsyncPublishInstance" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + else + #在Linux服务器上要求尽可能精确识别进程 + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $PROXY_HOME | grep -i "com.webank.eventmesh.http.demo.AsyncPublishInstance" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + fi + fi + echo "$ppid"; +} + + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" +elif [[ -d "$JAVA_HOME" ]] && is_java8 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" +elif is_java8 "/nemo/jdk8/bin/java"; then + JAVA="/nemo/jdk8/bin/java"; +elif is_java8 "/nemo/jdk1.8/bin/java"; then + JAVA="/nemo/jdk1.8/bin/java"; +elif is_java8 "/nemo/jdk/bin/java"; then + JAVA="/nemo/jdk/bin/java"; +elif is_java8 "$(which java)"; then + JAVA="$(which java)" +else + echo -e "ERROR\t java(1.8) not found, operation abort." + exit 9; +fi + +echo "http_pub_demo use java location= "$JAVA + +DEMO_HOME=`cd "./.." && pwd` + +export DEMO_HOME + +export DEMO_LOG_HOME=${DEMO_HOME}/logs + +echo "DEMO_HOME : ${DEMO_HOME}, DEMO_LOG_HOME : ${DEMO_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${DEMO_LOG_HOME}" ]; then mkdir -p "${DEMO_LOG_HOME}"; fi +} + +error_exit () +{ + echo "ERROR: $1 !!" + exit 1 +} + +export JAVA_HOME + +JAVA_OPT=`cat ${DEMO_HOME}/conf/server.env | grep APP_START_JVM_OPTION::: | awk -F ':::' {'print $2'}` +JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -XX:MaxGCPauseMillis=50" +JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${DEMO_HOME}/logs/demo_http_pub_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" +JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${DEMO_HOME}/logs -XX:ErrorFile=${PROXY_HOME}/logs/hs_err_%p.log" +JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" +JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow" +JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch" +JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=8G" +JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking" +JAVA_OPT="${JAVA_OPT} -Dio.netty.leakDetectionLevel=advanced" +JAVA_OPT="${JAVA_OPT} -Dio.netty.allocator.type=pooled" +JAVA_OPT="${JAVA_OPT} -Djava.security.egd=file:/dev/./urandom" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${DEMO_HOME}/conf/log4j2.xml" +#JAVA_OPT="${JAVA_OPT} -Dproxy.log.home=${DEMO_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${DEMO_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" +JAVA_OPT="${JAVA_OPT} -Drocketmq.client.logUseSlf4j=true" + +pid=$(get_pid) +if [ -n "$pid" ];then + echo -e "ERROR\t the server is already running (pid=$pid), there is no need to execute start.sh again." + exit 9; +fi + +make_logs_dir + +echo "using jdk[$JAVA]" >> ${DEMO_LOG_HOME}/demo_http_pub.out + + +DEMO_MAIN=com.webank.eventmesh.http.demo.AsyncPublishInstance +if [ $DOCKER ] +then + $JAVA $JAVA_OPT -classpath ${DEMO_HOME}/conf:${DEMO_HOME}/apps/*:${DEMO_HOME}/lib/* $DEMO_MAIN >> ${DEMO_LOG_HOME}/demo_http_pub.out +else + $JAVA $JAVA_OPT -classpath ${DEMO_HOME}/conf:${DEMO_HOME}/apps/*:${DEMO_HOME}/lib/* $DEMO_MAIN >> ${DEMO_LOG_HOME}/demo_http_pub.out 2>&1 & +echo $!>pid_http_pub.file +fi +exit 0 diff --git a/eventmesh-examples/bin/tcp_pub.sh b/eventmesh-examples/bin/tcp_pub.sh new file mode 100644 index 0000000000..d805ff868a --- /dev/null +++ b/eventmesh-examples/bin/tcp_pub.sh @@ -0,0 +1,135 @@ +#!/bin/sh + + +# Copyright (C) @2017 Webank Group Holding Limited +# +# Licensed 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. +# + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== +set -e +#服务器配置可能不一致,增加这些配置避免乱码问题 +export LANG=en_US.UTF-8 +export LC_CTYPE=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 + +TMP_JAVA_HOME="/nemo/jdk1.8.0_152" + +#detect operating system. +OS=$(uname -o) + +function is_java8 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' ]] || return 2 + return 0 +} + + +function get_pid { + local ppid="" + if [ -f ${DEMO_HOME}/bin/pid_tcp_pub.file ]; then + ppid=$(cat ${DEMO_HOME}/bin/pid_tcp_pub.file) + else + if [[ $OS =~ Msys ]]; then + # 在Msys上存在可能无法kill识别出的进程的BUG + ppid=`jps -v | grep -i "com.webank.eventmesh.tcp.demo.AsyncPublish" | grep java | grep -v grep | awk -F ' ' {'print $1'}` + elif [[ $OS =~ Darwin ]]; then + # 已知问题:grep java 可能无法精确识别java进程 + ppid=$(/bin/ps -o user,pid,command | grep "java" | grep -i "com.webank.eventmesh.tcp.demo.AsyncPublish" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + else + #在Linux服务器上要求尽可能精确识别进程 + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $PROXY_HOME | grep -i "com.webank.eventmesh.tcp.demo.AsyncPublish" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + fi + fi + echo "ppid"; +} + + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" +elif [[ -d "$JAVA_HOME" ]] && is_java8 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" +elif is_java8 "/nemo/jdk8/bin/java"; then + JAVA="/nemo/jdk8/bin/java"; +elif is_java8 "/nemo/jdk1.8/bin/java"; then + JAVA="/nemo/jdk1.8/bin/java"; +elif is_java8 "/nemo/jdk/bin/java"; then + JAVA="/nemo/jdk/bin/java"; +elif is_java8 "$(which java)"; then + JAVA="$(which java)" +else + echo -e "ERROR\t java(1.8) not found, operation abort." + exit 9; +fi + +echo "tcp_pub_demo use java location= "$JAVA + +DEMO_HOME=`cd "./.." && pwd` + +export DEMO_HOME + +export DEMO_LOG_HOME=${DEMO_HOME}/logs + +echo "DEMO_HOME : ${DEMO_HOME}, DEMO_LOG_HOME : ${DEMO_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${DEMO_LOG_HOME}" ]; then mkdir -p "${DEMO_LOG_HOME}"; fi +} + +error_exit () +{ + echo "ERROR: $1 !!" + exit 1 +} + +export JAVA_HOME + +JAVA_OPT=`cat ${DEMO_HOME}/conf/server.env | grep APP_START_JVM_OPTION::: | awk -F ':::' {'print $2'}` +JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -XX:MaxGCPauseMillis=50" +JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${DEMO_HOME}/logs/demo_tcp_pub_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" +JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${DEMO_HOME}/logs -XX:ErrorFile=${PROXY_HOME}/logs/hs_err_%p.log" +JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" +JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow" +JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch" +JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=8G" +JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking" +JAVA_OPT="${JAVA_OPT} -Dio.netty.leakDetectionLevel=advanced" +JAVA_OPT="${JAVA_OPT} -Dio.netty.allocator.type=pooled" +JAVA_OPT="${JAVA_OPT} -Djava.security.egd=file:/dev/./urandom" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${DEMO_HOME}/conf/log4j2.xml" +#JAVA_OPT="${JAVA_OPT} -Dproxy.log.home=${DEMO_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${DEMO_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" +JAVA_OPT="${JAVA_OPT} -Drocketmq.client.logUseSlf4j=true" + +pid=$(get_pid) +if [ -n "$pid" ];then + echo -e "ERROR\t the server is already running (pid=$pid), there is no need to execute start.sh again." + exit 9; +fi + +make_logs_dir + +echo "using jdk[$JAVA]" >> ${DEMO_LOG_HOME}/demo_tcp_pub.out + + +DEMO_MAIN=com.webank.eventmesh.tcp.demo.AsyncPublish +if [ $DOCKER ] +then + $JAVA $JAVA_OPT -classpath ${DEMO_HOME}/conf:${DEMO_HOME}/apps/*:${DEMO_HOME}/lib/* $DEMO_MAIN >> ${DEMO_LOG_HOME}/demo_tcp_pub.out +else + $JAVA $JAVA_OPT -classpath ${DEMO_HOME}/conf:${DEMO_HOME}/apps/*:${DEMO_HOME}/lib/* $DEMO_MAIN >> ${DEMO_LOG_HOME}/demo_tcp_pub.out 2>&1 & +echo $!>pid_tcp_pub.file +fi +exit 0 diff --git a/eventmesh-examples/bin/tcp_pub_broadcast.sh b/eventmesh-examples/bin/tcp_pub_broadcast.sh new file mode 100644 index 0000000000..8363dce52d --- /dev/null +++ b/eventmesh-examples/bin/tcp_pub_broadcast.sh @@ -0,0 +1,135 @@ +#!/bin/sh + + +# Copyright (C) @2017 Webank Group Holding Limited +# +# Licensed 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. +# + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== +set -e +#服务器配置可能不一致,增加这些配置避免乱码问题 +export LANG=en_US.UTF-8 +export LC_CTYPE=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 + +TMP_JAVA_HOME="/nemo/jdk1.8.0_152" + +#detect operating system. +OS=$(uname -o) + +function is_java8 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' ]] || return 2 + return 0 +} + + +function get_pid { + local ppid="" + if [ -f ${DEMO_HOME}/bin/pid_tcp_pub_broadcast.file ]; then + ppid=$(cat ${DEMO_HOME}/bin/pid_tcp_pub_broadcast.file) + else + if [[ $OS =~ Msys ]]; then + # 在Msys上存在可能无法kill识别出的进程的BUG + ppid=`jps -v | grep -i "com.webank.eventmesh.tcp.demo.AsyncPublishBroadcast" | grep java | grep -v grep | awk -F ' ' {'print $1'}` + elif [[ $OS =~ Darwin ]]; then + # 已知问题:grep java 可能无法精确识别java进程 + ppid=$(/bin/ps -o user,pid,command | grep "java" | grep -i "com.webank.eventmesh.tcp.demo.AsyncPublishBroadcast" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + else + #在Linux服务器上要求尽可能精确识别进程 + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $DEMO_HOME | grep -i "com.webank.eventmesh.tcp.demo.AsyncPublishBroadcast" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + fi + fi + echo "$ppid"; +} + + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" +elif [[ -d "$JAVA_HOME" ]] && is_java8 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" +elif is_java8 "/nemo/jdk8/bin/java"; then + JAVA="/nemo/jdk8/bin/java"; +elif is_java8 "/nemo/jdk1.8/bin/java"; then + JAVA="/nemo/jdk1.8/bin/java"; +elif is_java8 "/nemo/jdk/bin/java"; then + JAVA="/nemo/jdk/bin/java"; +elif is_java8 "$(which java)"; then + JAVA="$(which java)" +else + echo -e "ERROR\t java(1.8) not found, operation abort." + exit 9; +fi + +echo "tcp_pub_demo use java location= "$JAVA + +DEMO_HOME=`cd "./.." && pwd` + +export DEMO_HOME + +export DEMO_LOG_HOME=${DEMO_HOME}/logs + +echo "DEMO_HOME : ${DEMO_HOME}, DEMO_LOG_HOME : ${DEMO_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${DEMO_LOG_HOME}" ]; then mkdir -p "${DEMO_LOG_HOME}"; fi +} + +error_exit () +{ + echo "ERROR: $1 !!" + exit 1 +} + +export JAVA_HOME + +JAVA_OPT=`cat ${DEMO_HOME}/conf/server.env | grep APP_START_JVM_OPTION::: | awk -F ':::' {'print $2'}` +JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -XX:MaxGCPauseMillis=50" +JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${DEMO_HOME}/logs/demo_tcp_pub_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" +JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${DEMO_HOME}/logs -XX:ErrorFile=${DEMO_HOME}/logs/hs_err_%p.log" +JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" +JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow" +JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch" +JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=8G" +JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking" +JAVA_OPT="${JAVA_OPT} -Dio.netty.leakDetectionLevel=advanced" +JAVA_OPT="${JAVA_OPT} -Dio.netty.allocator.type=pooled" +JAVA_OPT="${JAVA_OPT} -Djava.security.egd=file:/dev/./urandom" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${DEMO_HOME}/conf/log4j2.xml" +#JAVA_OPT="${JAVA_OPT} -Dproxy.log.home=${DEMO_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${DEMO_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" +JAVA_OPT="${JAVA_OPT} -Drocketmq.client.logUseSlf4j=true" + +pid=$(get_pid) +if [ -n "$pid" ];then + echo -e "ERROR\t the server is already running (pid=$pid), there is no need to execute start.sh again." + exit 9; +fi + +make_logs_dir + +echo "using jdk[$JAVA]" >> ${DEMO_LOG_HOME}/demo_tcp_pub_broadcast.out + + +DEMO_MAIN=com.webank.eventmesh.tcp.demo.AsyncPublishBroadcast +if [ $DOCKER ] +then + $JAVA $JAVA_OPT -classpath ${DEMO_HOME}/conf:${DEMO_HOME}/apps/*:${DEMO_HOME}/lib/* $DEMO_MAIN >> ${DEMO_LOG_HOME}/demo_tcp_pub_broadcast.out +else + $JAVA $JAVA_OPT -classpath ${DEMO_HOME}/conf:${DEMO_HOME}/apps/*:${DEMO_HOME}/lib/* $DEMO_MAIN >> ${DEMO_LOG_HOME}/demo_tcp_pub_broadcast.out 2>&1 & +echo $!>pid_tcp_pub_broadcast.file +fi +exit 0 diff --git a/eventmesh-examples/bin/tcp_sub.sh b/eventmesh-examples/bin/tcp_sub.sh new file mode 100644 index 0000000000..c1a864483e --- /dev/null +++ b/eventmesh-examples/bin/tcp_sub.sh @@ -0,0 +1,135 @@ +#!/bin/sh + + +# Copyright (C) @2017 Webank Group Holding Limited +# +# Licensed 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. +# + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== +set -e +#服务器配置可能不一致,增加这些配置避免乱码问题 +export LANG=en_US.UTF-8 +export LC_CTYPE=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 + +TMP_JAVA_HOME="/nemo/jdk1.8.0_152" + +#detect operating system. +OS=$(uname -o) + +function is_java8 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' ]] || return 2 + return 0 +} + + +function get_pid { + local ppid="" + if [ -f ${DEMO_HOME}/bin/pid_tcp_sub.file ]; then + ppid=$(cat ${DEMO_HOME}/bin/pid_tcp_sub.file) + else + if [[ $OS =~ Msys ]]; then + # 在Msys上存在可能无法kill识别出的进程的BUG + ppid=`jps -v | grep -i "com.webank.eventmesh.tcp.demo.AsyncSubscribe" | grep java | grep -v grep | awk -F ' ' {'print $1'}` + elif [[ $OS =~ Darwin ]]; then + # 已知问题:grep java 可能无法精确识别java进程 + ppid=$(/bin/ps -o user,pid,command | grep "java" | grep -i "com.webank.eventmesh.tcp.demo.AsyncSubscribe" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + else + #在Linux服务器上要求尽可能精确识别进程 + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $DEMO_HOME | grep -i "com.webank.eventmesh.tcp.demo.AsyncSubscribe" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + fi + fi + echo "$ppid"; +} + + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" +elif [[ -d "$JAVA_HOME" ]] && is_java8 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" +elif is_java8 "/nemo/jdk8/bin/java"; then + JAVA="/nemo/jdk8/bin/java"; +elif is_java8 "/nemo/jdk1.8/bin/java"; then + JAVA="/nemo/jdk1.8/bin/java"; +elif is_java8 "/nemo/jdk/bin/java"; then + JAVA="/nemo/jdk/bin/java"; +elif is_java8 "$(which java)"; then + JAVA="$(which java)" +else + echo -e "ERROR\t java(1.8) not found, operation abort." + exit 9; +fi + +echo "tcp_sub_demo use java location= "$JAVA + +DEMO_HOME=`cd "./.." && pwd` + +export DEMO_HOME + +export DEMO_LOG_HOME=${DEMO_HOME}/logs + +echo "DEMO_HOME : ${DEMO_HOME}, DEMO_LOG_HOME : ${DEMO_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${DEMO_LOG_HOME}" ]; then mkdir -p "${DEMO_LOG_HOME}"; fi +} + +error_exit () +{ + echo "ERROR: $1 !!" + exit 1 +} + +export JAVA_HOME + +JAVA_OPT=`cat ${DEMO_HOME}/conf/server.env | grep APP_START_JVM_OPTION::: | awk -F ':::' {'print $2'}` +JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -XX:MaxGCPauseMillis=50" +JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${DEMO_HOME}/logs/demo_tcp_sub_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" +JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${DEMO_HOME}/logs -XX:ErrorFile=${DEMO_HOME}/logs/hs_err_%p.log" +JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" +JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow" +JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch" +JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=8G" +JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking" +JAVA_OPT="${JAVA_OPT} -Dio.netty.leakDetectionLevel=advanced" +JAVA_OPT="${JAVA_OPT} -Dio.netty.allocator.type=pooled" +JAVA_OPT="${JAVA_OPT} -Djava.security.egd=file:/dev/./urandom" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${DEMO_HOME}/conf/log4j2.xml" +#JAVA_OPT="${JAVA_OPT} -Dproxy.log.home=${DEMO_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${DEMO_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" +JAVA_OPT="${JAVA_OPT} -Drocketmq.client.logUseSlf4j=true" + +pid=$(get_pid) +if [ -n "$pid" ];then + echo -e "ERROR\t the server is already running (pid=$pid), there is no need to execute start.sh again." + exit 9; +fi + +make_logs_dir + +echo "using jdk[$JAVA]" >> ${DEMO_LOG_HOME}/demo_tcp_sub.out + + +DEMO_MAIN=com.webank.eventmesh.tcp.demo.AsyncSubscribe +if [ $DOCKER ] +then + $JAVA $JAVA_OPT -classpath ${DEMO_HOME}/conf:${DEMO_HOME}/apps/*:${DEMO_HOME}/lib/* $DEMO_MAIN >> ${DEMO_LOG_HOME}/demo_tcp_sub.out +else + $JAVA $JAVA_OPT -classpath ${DEMO_HOME}/conf:${DEMO_HOME}/apps/*:${DEMO_HOME}/lib/* $DEMO_MAIN >> ${DEMO_LOG_HOME}/demo_tcp_sub.out 2>&1 & +echo $!>pid_tcp_sub.file +fi +exit 0 diff --git a/eventmesh-examples/bin/tcp_sub_broadcast.sh b/eventmesh-examples/bin/tcp_sub_broadcast.sh new file mode 100644 index 0000000000..b40176b9f6 --- /dev/null +++ b/eventmesh-examples/bin/tcp_sub_broadcast.sh @@ -0,0 +1,135 @@ +#!/bin/sh + + +# Copyright (C) @2017 Webank Group Holding Limited +# +# Licensed 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. +# + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== +set -e +#服务器配置可能不一致,增加这些配置避免乱码问题 +export LANG=en_US.UTF-8 +export LC_CTYPE=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 + +TMP_JAVA_HOME="/nemo/jdk1.8.0_152" + +#detect operating system. +OS=$(uname -o) + +function is_java8 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' ]] || return 2 + return 0 +} + + +function get_pid { + local ppid="" + if [ -f ${PROXY_HOME}/bin/pid_tcp_sub_broadcast.file ]; then + ppid=$(cat ${PROXY_HOME}/bin/pid_tcp_sub_broadcast.file) + else + if [[ $OS =~ Msys ]]; then + # 在Msys上存在可能无法kill识别出的进程的BUG + ppid=`jps -v | grep -i "com.webank.eventmesh.tcp.demo.AsyncSubscribeBroadcast" | grep java | grep -v grep | awk -F ' ' {'print $1'}` + elif [[ $OS =~ Darwin ]]; then + # 已知问题:grep java 可能无法精确识别java进程 + ppid=$(/bin/ps -o user,pid,command | grep "java" | grep -i "com.webank.eventmesh.tcp.demo.AsyncSubscribeBroadcast" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + else + #在Linux服务器上要求尽可能精确识别进程 + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $PROXY_HOME | grep -i "com.webank.eventmesh.tcp.demo.AsyncSubscribeBroadcast" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + fi + fi + echo "$ppid"; +} + + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" +elif [[ -d "$JAVA_HOME" ]] && is_java8 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" +elif is_java8 "/nemo/jdk8/bin/java"; then + JAVA="/nemo/jdk8/bin/java"; +elif is_java8 "/nemo/jdk1.8/bin/java"; then + JAVA="/nemo/jdk1.8/bin/java"; +elif is_java8 "/nemo/jdk/bin/java"; then + JAVA="/nemo/jdk/bin/java"; +elif is_java8 "$(which java)"; then + JAVA="$(which java)" +else + echo -e "ERROR\t java(1.8) not found, operation abort." + exit 9; +fi + +echo "tcp_sub_demo use java location= "$JAVA + +DEMO_HOME=`cd "./.." && pwd` + +export DEMO_HOME + +export DEMO_LOG_HOME=${DEMO_HOME}/logs + +echo "DEMO_HOME : ${DEMO_HOME}, DEMO_LOG_HOME : ${DEMO_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${DEMO_LOG_HOME}" ]; then mkdir -p "${DEMO_LOG_HOME}"; fi +} + +error_exit () +{ + echo "ERROR: $1 !!" + exit 1 +} + +export JAVA_HOME + +JAVA_OPT=`cat ${DEMO_HOME}/conf/server.env | grep APP_START_JVM_OPTION::: | awk -F ':::' {'print $2'}` +JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -XX:MaxGCPauseMillis=50" +JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${DEMO_HOME}/logs/demo_tcp_sub_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" +JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${DEMO_HOME}/logs -XX:ErrorFile=${DEMO_HOME}/logs/hs_err_%p.log" +JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" +JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow" +JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch" +JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=8G" +JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking" +JAVA_OPT="${JAVA_OPT} -Dio.netty.leakDetectionLevel=advanced" +JAVA_OPT="${JAVA_OPT} -Dio.netty.allocator.type=pooled" +JAVA_OPT="${JAVA_OPT} -Djava.security.egd=file:/dev/./urandom" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${DEMO_HOME}/conf/log4j2.xml" +#JAVA_OPT="${JAVA_OPT} -Dproxy.log.home=${DEMO_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${DEMO_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" +JAVA_OPT="${JAVA_OPT} -Drocketmq.client.logUseSlf4j=true" + +pid=$(get_pid) +if [ -n "$pid" ];then + echo -e "ERROR\t the server is already running (pid=$pid), there is no need to execute start.sh again." + exit 9; +fi + +make_logs_dir + +echo "using jdk[$JAVA]" >> ${DEMO_LOG_HOME}/demo_tcp_sub_broadcast.out + + +DEMO_MAIN=com.webank.eventmesh.tcp.demo.AsyncSubscribeBroadcast +if [ $DOCKER ] +then + $JAVA $JAVA_OPT -classpath ${DEMO_HOME}/conf:${DEMO_HOME}/apps/*:${DEMO_HOME}/lib/* $DEMO_MAIN >> ${DEMO_LOG_HOME}/demo_tcp_sub_broadcast.out +else + $JAVA $JAVA_OPT -classpath ${DEMO_HOME}/conf:${DEMO_HOME}/apps/*:${DEMO_HOME}/lib/* $DEMO_MAIN >> ${DEMO_LOG_HOME}/demo_tcp_sub_broadcast.out 2>&1 & +echo $!>pid_tcp_sub_broadcast.file +fi +exit 0 diff --git a/eventmesh-examples/conf/application.properties b/eventmesh-examples/conf/application.properties new file mode 100644 index 0000000000..2886a8c218 --- /dev/null +++ b/eventmesh-examples/conf/application.properties @@ -0,0 +1,4 @@ +server.port=8088 +eventmesh.ip=127.0.0.1 +eventmesh.http.port=10105 +eventmesh.tcp.port=10000 \ No newline at end of file diff --git a/eventmesh-examples/conf/log4j2.xml b/eventmesh-examples/conf/log4j2.xml new file mode 100644 index 0000000000..1483ca35fd --- /dev/null +++ b/eventmesh-examples/conf/log4j2.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eventmesh-examples/conf/server.env b/eventmesh-examples/conf/server.env new file mode 100644 index 0000000000..77e68cefeb --- /dev/null +++ b/eventmesh-examples/conf/server.env @@ -0,0 +1 @@ +APP_START_JVM_OPTION:::-server -Xms64M -Xmx128M -Xmn64m -XX:SurvivorRatio=4 -Duser.language=zh diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/common/EventMeshTestCaseTopicSet.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/common/EventMeshTestCaseTopicSet.java new file mode 100644 index 0000000000..dbc8d0b248 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/common/EventMeshTestCaseTopicSet.java @@ -0,0 +1,17 @@ +package org.apache.eventmesh.tcp.common; + +/** + * Testcase set + */ +public class EventMeshTestCaseTopicSet { + +// public static final String TOPIC_PRX_WQ2ClientBroadCast = "topic-broadcast-test"; + public static final String TOPIC_PRX_WQ2ClientBroadCast = "FT0-e-80030000-01-3"; + +// public static final String TOPIC_PRX_SyncSubscribeTest = "topic-sync-test"; + public static final String TOPIC_PRX_SyncSubscribeTest = "FT0-s-80000000-01-0"; + +// public static final String TOPIC_PRX_WQ2ClientUniCast = "topic-async-test"; + public static final String TOPIC_PRX_WQ2ClientUniCast = "FT0-e-80010000-01-1"; + +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/build.gradle b/eventmesh-metrics-plugin/eventmesh-metrics-api/build.gradle index ddc5f43270..da49b3a695 100644 --- a/eventmesh-metrics-plugin/eventmesh-metrics-api/build.gradle +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/build.gradle @@ -28,6 +28,5 @@ dependencies { testAnnotationProcessor 'org.projectlombok:lombok' testImplementation "org.mockito:mockito-core" - testImplementation "org.mockito:mockito-inline" } diff --git a/eventmesh-registry-plugin/eventmesh-registry-zookeeper/build.gradle b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/build.gradle new file mode 100644 index 0000000000..006f9a1812 --- /dev/null +++ b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/build.gradle @@ -0,0 +1,28 @@ +/* + * 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. + */ + +dependencies { + implementation 'log4j:log4j:1.2.17' + implementation 'org.apache.zookeeper:zookeeper:3.4.6' + implementation 'org.apache.curator:curator-client:4.0.1' + implementation 'org.apache.curator:curator-framework:4.0.1' + implementation 'org.apache.curator:curator-recipes:4.0.1' + implementation project(":eventmesh-registry-plugin:eventmesh-registry-api") + implementation project(":eventmesh-common") + testImplementation 'org.mockito:mockito-core' + testImplementation 'org.apache.curator:curator-test:2.12.0' +} diff --git a/eventmesh-registry-plugin/eventmesh-registry-zookeeper/gradle.properties b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/gradle.properties new file mode 100644 index 0000000000..1743025814 --- /dev/null +++ b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/gradle.properties @@ -0,0 +1,18 @@ +# 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. +# + +pluginType=registry +pluginName=zookeeper \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/java/org/apache/eventmesh/registry/zookeeper/constant/ZookeeperConstant.java b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/java/org/apache/eventmesh/registry/zookeeper/constant/ZookeeperConstant.java new file mode 100644 index 0000000000..9d0ba356ad --- /dev/null +++ b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/java/org/apache/eventmesh/registry/zookeeper/constant/ZookeeperConstant.java @@ -0,0 +1,34 @@ +/* + * 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.registry.zookeeper.constant; + +/** + * ZookeeperConstant. + */ +public class ZookeeperConstant { + + public static final String NAMESPACE = "eventmesh-zcy"; + + public static final String IP_PORT_SEPARATOR = ":"; + + public static final int SESSION_TIME_OUT = 2000; + + public static final String DEFAULT_GROUP = "DEFAULT_GROUP"; + + public static final String PATH_SEPARATOR = "/"; +} diff --git a/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/java/org/apache/eventmesh/registry/zookeeper/service/ZookeeperRegistryService.java b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/java/org/apache/eventmesh/registry/zookeeper/service/ZookeeperRegistryService.java new file mode 100644 index 0000000000..569510ee20 --- /dev/null +++ b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/java/org/apache/eventmesh/registry/zookeeper/service/ZookeeperRegistryService.java @@ -0,0 +1,228 @@ +/* + * 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.registry.zookeeper.service; + + +import com.google.common.collect.Maps; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.curator.RetryPolicy; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.eventmesh.api.exception.RegistryException; +import org.apache.eventmesh.api.registry.RegistryService; +import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.registry.zookeeper.constant.ZookeeperConstant; +import org.apache.eventmesh.registry.zookeeper.util.JsonUtils; +import org.apache.zookeeper.CreateMode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +public class ZookeeperRegistryService implements RegistryService { + + private static final Logger logger = LoggerFactory.getLogger(ZookeeperRegistryService.class); + + private static final AtomicBoolean INIT_STATUS = new AtomicBoolean(false); + + private static final AtomicBoolean START_STATUS = new AtomicBoolean(false); + + private String serverAddr; + + public CuratorFramework zkClient = null; + + + @Override + public void init() throws RegistryException { + boolean update = INIT_STATUS.compareAndSet(false, true); + if (!update) { + return; + } + + for (String key : ConfigurationContextUtil.KEYS) { + CommonConfiguration commonConfiguration = ConfigurationContextUtil.get(key); + if (null == commonConfiguration) { + continue; + } + if (StringUtils.isBlank(commonConfiguration.namesrvAddr)) { + throw new RegistryException("namesrvAddr cannot be null"); + } + this.serverAddr = commonConfiguration.namesrvAddr; + break; + } + } + + @Override + public void start() throws RegistryException { + boolean update = START_STATUS.compareAndSet(false, true); + if (!update) { + return; + } + try { + RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 5); + + zkClient = CuratorFrameworkFactory.builder() + .connectString(serverAddr) + .sessionTimeoutMs(ZookeeperConstant.SESSION_TIME_OUT) + .retryPolicy(retryPolicy) + .namespace(ZookeeperConstant.NAMESPACE) + .build(); + zkClient.start(); + + } catch (Exception e) { + logger.error("[ZookeeperRegistryService][start] error", e); + throw new RegistryException(e.getMessage()); + } + } + + @Override + public void shutdown() throws RegistryException { + INIT_STATUS.compareAndSet(true, false); + START_STATUS.compareAndSet(true, false); + try { + zkClient.close(); + } catch (Exception e) { + logger.error("[ZookeeperRegistryService][shutdown] error", e); + throw new RegistryException(e.getMessage()); + } + logger.info("ZookeeperRegistryService close"); + } + + @Override + public List findEventMeshInfoByCluster(String clusterName) throws RegistryException { + List eventMeshDataInfoList = new ArrayList<>(); + for (String key : ConfigurationContextUtil.KEYS) { + CommonConfiguration configuration = ConfigurationContextUtil.get(key); + if (Objects.isNull(configuration)) { + continue; + } + String eventMeshName = configuration.eventMeshName; + try { + + String serviceName = eventMeshName.concat("-").concat(key); + String clusterPath = formatServicePath(clusterName,serviceName); + + List instances = zkClient.getChildren().forPath(clusterPath); + + if (CollectionUtils.isEmpty(instances)) { + continue; + } + + eventMeshDataInfoList = instances.stream() + .map(p -> new EventMeshDataInfo(clusterName, serviceName, p, 0L)) + .collect(Collectors.toList()); + + } catch (Exception e) { + logger.error("[ZookeeperRegistryService][findEventMeshInfoByCluster] error", e); + throw new RegistryException(e.getMessage()); + } + + } + return eventMeshDataInfoList; + } + + @Override + public Map> findEventMeshClientDistributionData(String clusterName, String group, String purpose) + throws RegistryException { + // todo find metadata + return null; + } + + @Override + public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws RegistryException { + try { + + String[] ipPort = eventMeshRegisterInfo.getEndPoint().split(ZookeeperConstant.IP_PORT_SEPARATOR); + String ip = ipPort[0]; + Integer port = Integer.valueOf(ipPort[1]); + String eventMeshName = eventMeshRegisterInfo.getEventMeshName(); + String eventMeshClusterName = eventMeshRegisterInfo.getEventMeshClusterName(); + Map> instanceNumMap = eventMeshRegisterInfo.getEventMeshInstanceNumMap(); + + // clusterName/eventMeshName/ip:port + String path = formatInstancePath(eventMeshClusterName,eventMeshName,eventMeshRegisterInfo.getEndPoint()); + + HashMap dataMap = Maps.newHashMap(); + dataMap.put("ip", ip); + dataMap.put("port", port); + dataMap.put("weight", 1.0); + dataMap.put("instanceNumMap", instanceNumMap); + + zkClient.create() + .creatingParentsIfNeeded() + .withMode(CreateMode.EPHEMERAL) + .forPath(path, JsonUtils.toJSON(dataMap).getBytes(Charset.forName("utf-8"))); + + } catch (Exception e) { + logger.error("[ZookeeperRegistryService][register] error", e); + throw new RegistryException(e.getMessage()); + } + logger.info("EventMesh successfully registered to zookeeper"); + return true; + } + + @Override + public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws RegistryException { + try { + String eventMeshName = eventMeshUnRegisterInfo.getEventMeshName(); + String eventMeshClusterName = eventMeshUnRegisterInfo.getEventMeshClusterName(); + + String path = formatInstancePath(eventMeshClusterName,eventMeshName,eventMeshUnRegisterInfo.getEndPoint()); + + zkClient.delete().forPath(path); + } catch (Exception e) { + logger.error("[ZookeeperRegistryService][unRegister] error", e); + throw new RegistryException(e.getMessage()); + } + logger.info("EventMesh successfully logout to zookeeper"); + return true; + } + + private String formatInstancePath(String clusterName, String serviceName, String endPoint){ + return ZookeeperConstant.PATH_SEPARATOR.concat(clusterName) + .concat(ZookeeperConstant.PATH_SEPARATOR).concat(serviceName) + .concat(ZookeeperConstant.PATH_SEPARATOR).concat(endPoint); + } + + private String formatServicePath(String clusterName,String serviceName){ + return ZookeeperConstant.PATH_SEPARATOR.concat(clusterName) + .concat(ZookeeperConstant.PATH_SEPARATOR).concat(serviceName); + } + + public String getServerAddr() { + return serverAddr; + } + + public CuratorFramework getZkClient() { + return zkClient; + } +} diff --git a/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/java/org/apache/eventmesh/registry/zookeeper/util/JsonUtils.java b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/java/org/apache/eventmesh/registry/zookeeper/util/JsonUtils.java new file mode 100644 index 0000000000..0893bc9c19 --- /dev/null +++ b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/java/org/apache/eventmesh/registry/zookeeper/util/JsonUtils.java @@ -0,0 +1,23 @@ +package org.apache.eventmesh.registry.zookeeper.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * @Author: moxing + * @Date: 2022/6/17 13:57 + * @Description: + */ +public class JsonUtils { + + public static String toJSON(Object o) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + String string = objectMapper.writeValueAsString(o); + return string; + } catch (JsonProcessingException e) { + return null; + } + } + +} diff --git a/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService new file mode 100644 index 0000000000..82909f46a9 --- /dev/null +++ b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService @@ -0,0 +1,16 @@ +# 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. + +zookeeper=org.apache.eventmesh.registry.zookeeper.service.ZookeeperRegistryService \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/test/java/org/apache/eventmesh/registry/zookeeper/service/ZookeeperRegistryServiceTest.java b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/test/java/org/apache/eventmesh/registry/zookeeper/service/ZookeeperRegistryServiceTest.java new file mode 100644 index 0000000000..17d30400d9 --- /dev/null +++ b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/test/java/org/apache/eventmesh/registry/zookeeper/service/ZookeeperRegistryServiceTest.java @@ -0,0 +1,148 @@ +/* + * 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.registry.zookeeper.service; + +import com.google.common.collect.Maps; + +import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; + +import org.apache.curator.test.TestingServer; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.lang.reflect.Field; +import java.util.List; + +@RunWith(MockitoJUnitRunner.class) +public class ZookeeperRegistryServiceTest { + + @Mock + private EventMeshRegisterInfo eventMeshRegisterInfo; + @Mock + private EventMeshUnRegisterInfo eventMeshUnRegisterInfo; + + private ZookeeperRegistryService zkRegistryService; + + private TestingServer testingServer; + + @Before + public void setUp() throws Exception { + testingServer = new TestingServer(1500, true); + testingServer.start(); + + zkRegistryService = new ZookeeperRegistryService(); + CommonConfiguration configuration = new CommonConfiguration(null); + configuration.namesrvAddr = "127.0.0.1:1500"; + configuration.eventMeshName = "eventmesh"; + ConfigurationContextUtil.putIfAbsent(ConfigurationContextUtil.HTTP, configuration); + + Mockito.when(eventMeshRegisterInfo.getEventMeshClusterName()).thenReturn("eventmeshCluster"); + Mockito.when(eventMeshRegisterInfo.getEventMeshName()).thenReturn("eventmesh-" + ConfigurationContextUtil.HTTP); + Mockito.when(eventMeshRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:8848"); + Mockito.when(eventMeshRegisterInfo.getEventMeshInstanceNumMap()).thenReturn(Maps.newHashMap()); + + Mockito.when(eventMeshUnRegisterInfo.getEventMeshClusterName()).thenReturn("eventmeshCluster"); + Mockito.when(eventMeshUnRegisterInfo.getEventMeshName()).thenReturn("eventmesh-" + ConfigurationContextUtil.HTTP); + Mockito.when(eventMeshUnRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:8848"); + } + + @After + public void after() throws Exception { + zkRegistryService.shutdown(); + testingServer.close(); + } + + @Test + public void testInit() { + zkRegistryService.init(); + zkRegistryService.start(); + Assert.assertNotNull(zkRegistryService.getServerAddr()); + } + + @Test + public void testStart() { + zkRegistryService.init(); + zkRegistryService.start(); + Assert.assertNotNull(zkRegistryService.getZkClient()); + } + + @Test + public void testShutdown() throws NoSuchFieldException, IllegalAccessException { + zkRegistryService.init(); + zkRegistryService.start(); + zkRegistryService.shutdown(); + + Class zkRegistryServiceClass = ZookeeperRegistryService.class; + Field initStatus = zkRegistryServiceClass.getDeclaredField("INIT_STATUS"); + initStatus.setAccessible(true); + Object initStatusField = initStatus.get(zkRegistryService); + + Field startStatus = zkRegistryServiceClass.getDeclaredField("START_STATUS"); + startStatus.setAccessible(true); + Object startStatusField = startStatus.get(zkRegistryService); + + Assert.assertFalse((Boolean.parseBoolean(initStatusField.toString()))); + Assert.assertFalse((Boolean.parseBoolean(startStatusField.toString()))); + } + + + @Test + public void testFindEventMeshInfoByCluster() { + zkRegistryService.init(); + zkRegistryService.start(); + zkRegistryService.register(eventMeshRegisterInfo); + // Setup + // Run the test + + final List result = zkRegistryService.findEventMeshInfoByCluster(eventMeshRegisterInfo.getEventMeshClusterName()); + + // Verify the results + Assert.assertNotNull(result); + } + + @Test() + public void testRegister() { + zkRegistryService.init(); + zkRegistryService.start(); + zkRegistryService.register(eventMeshRegisterInfo); + } + + @Test() + public void testUnRegister() { + zkRegistryService.init(); + zkRegistryService.start(); + boolean register = zkRegistryService.register(eventMeshRegisterInfo); + + Assert.assertTrue(register); + + boolean unRegister = zkRegistryService.unRegister(eventMeshUnRegisterInfo); + + Assert.assertTrue(unRegister); + } +} \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/test/resources/log4j.properties b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/test/resources/log4j.properties new file mode 100644 index 0000000000..746168484d --- /dev/null +++ b/eventmesh-registry-plugin/eventmesh-registry-zookeeper/src/test/resources/log4j.properties @@ -0,0 +1,18 @@ +log4j.rootLogger=info, stdout, R + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout + +# Pattern to output the caller's file name and line number. +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n + +log4j.appender.R=org.apache.log4j.RollingFileAppender +log4j.appender.R.File=example.log + +log4j.appender.R.MaxFileSize=100KB +# Keep one backup file +log4j.appender.R.MaxBackupIndex=5 + +log4j.appender.R.layout=org.apache.log4j.PatternLayout +log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n + diff --git a/eventmesh-retry/eventmesh-retry-kafka/build.gradle b/eventmesh-retry/eventmesh-retry-kafka/build.gradle new file mode 100644 index 0000000000..596b4fb7f9 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-kafka/build.gradle @@ -0,0 +1,32 @@ +/* + * 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. + */ + + +dependencies { + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-kafka") + implementation project(":eventmesh-retry:eventmesh-retry-api") + implementation project(":eventmesh-common") + + implementation 'io.cloudevents:cloudevents-core' + implementation 'io.cloudevents:cloudevents-json-jackson' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation 'org.junit.jupiter:junit-jupiter' +} \ No newline at end of file diff --git a/eventmesh-retry/eventmesh-retry-kafka/gradle.properties b/eventmesh-retry/eventmesh-retry-kafka/gradle.properties new file mode 100644 index 0000000000..30b50a9585 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-kafka/gradle.properties @@ -0,0 +1,19 @@ +# 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. +# + +kafka_version=3.7.1 +pluginType=retry +pluginName=kafka \ No newline at end of file diff --git a/eventmesh-retry/eventmesh-retry-kafka/src/main/java/org/apache/eventmesh/retry/kafka/KafkaRetryStrategyImpl.java b/eventmesh-retry/eventmesh-retry-kafka/src/main/java/org/apache/eventmesh/retry/kafka/KafkaRetryStrategyImpl.java new file mode 100644 index 0000000000..b872a10fb7 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-kafka/src/main/java/org/apache/eventmesh/retry/kafka/KafkaRetryStrategyImpl.java @@ -0,0 +1,71 @@ +/* + * 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.retry.kafka; + +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.api.producer.Producer; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.retry.api.conf.RetryConfiguration; +import org.apache.eventmesh.retry.api.strategy.RetryStrategy; + +import java.util.Objects; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class KafkaRetryStrategyImpl implements RetryStrategy { + + @Override + public void retry(RetryConfiguration configuration) { + sendMessageBack(configuration); + } + + @SneakyThrows + private void sendMessageBack(final RetryConfiguration configuration) { + CloudEvent event = configuration.getEvent(); + String topic = configuration.getTopic(); + String consumerGroupName = configuration.getConsumerGroupName(); + + String bizSeqNo = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.BIZSEQNO.getKey())).toString(); + String uniqueId = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.UNIQUEID.getKey())).toString(); + CloudEvent retryEvent = CloudEventBuilder.from(event) + .withSubject(topic) + .build(); + Producer producer = configuration.getProducer(); + producer.publish(retryEvent, new SendCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + log.info("consumer:{} consume success,, bizSeqno:{}, uniqueId:{}", + consumerGroupName, bizSeqNo, uniqueId); + } + + @Override + public void onException(OnExceptionContext context) { + log.warn("consumer:{} consume fail, sendMessageBack, bizSeqno:{}, uniqueId:{}", + consumerGroupName, bizSeqNo, uniqueId, context.getException()); + } + }); + } +} diff --git a/eventmesh-retry/eventmesh-retry-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.retry.api.strategy.RetryStrategy b/eventmesh-retry/eventmesh-retry-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.retry.api.strategy.RetryStrategy new file mode 100644 index 0000000000..1e8e23da20 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.retry.api.strategy.RetryStrategy @@ -0,0 +1,16 @@ +# 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. + +kafka=org.apache.eventmesh.retry.kafka.KafkaRetryStrategyImpl \ No newline at end of file diff --git a/eventmesh-retry/eventmesh-retry-rocketmq/gradle.properties b/eventmesh-retry/eventmesh-retry-rocketmq/gradle.properties index 5114e05231..27dcaff9bd 100644 --- a/eventmesh-retry/eventmesh-retry-rocketmq/gradle.properties +++ b/eventmesh-retry/eventmesh-retry-rocketmq/gradle.properties @@ -14,6 +14,10 @@ # limitations under the License. # +<<<<<<<< HEAD:eventmesh-retry/eventmesh-retry-rocketmq/gradle.properties rocketmq_version=4.9.5 pluginType=retry -pluginName=rocketmq \ No newline at end of file +pluginName=rocketmq +======== +standalone=org.apache.eventmesh.connector.standalone.producer.StandaloneProducerAdaptor +>>>>>>>> 113b813a1 (Fix standalone connector interface, fix example (#608)):eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer diff --git a/eventmesh-runtime/conf/log-client.properties b/eventmesh-runtime/conf/log-client.properties new file mode 100644 index 0000000000..566382dc3a --- /dev/null +++ b/eventmesh-runtime/conf/log-client.properties @@ -0,0 +1,26 @@ +# +# 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. +# + +logserver.client.start.up=true +logserver.client.open=true +logserver.client.env=test +logserver.client.system.id= +logserver.client.system.dcn= +logserver.client.system.org= +logserver.client.system.idc= +logserver.client.memory.full.loglevel=error +client.ws.addrs= \ No newline at end of file diff --git a/eventmesh-runtime/conf/proxy.properties b/eventmesh-runtime/conf/proxy.properties new file mode 100644 index 0000000000..2bae9d5316 --- /dev/null +++ b/eventmesh-runtime/conf/proxy.properties @@ -0,0 +1,81 @@ +# +# 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. +# + +###############################PROXY ENV################################# +#### proxyEnv -> proxyRegion(\u533A\u57DF:SZ/SH) -> proxyIdc -> proxyDcn(1C0) -> proxyCluster(\u96C6\u7FA4:LS/CNC/DEP) -> proxyIp #### +proxy.server.idc=DEFAULT +proxy.server.env=PRD +proxy.server.region=region1 +proxy.server.cluster=COMMON +proxy.server.name=EVNETMESH-EMESHER +proxy.server.dcn= +proxy.sysid=0000 +proxy.server.http.port=10105 + +#######################defibus################## +#proxy.server.defibus.configCenter= +proxy.server.defibus.client.consumeThreadMin=2 +proxy.server.defibus.client.consumeThreadMax=2 +proxy.server.defibus.client.consumeThreadPoolQueueSize=10000 +proxy.server.defibus.client.pullBatchSize=32 +proxy.server.defibus.client.ackwindow=1000 +proxy.server.defibus.client.pubwindow=512 +proxy.server.defibus.client.pollNameServerInterval=10000 +proxy.server.defibus.client.heartbeatBrokerInterval=30000 +proxy.server.defibus.client.rebalanceInterval=20000 + +########################## proxy tcp\u76F8\u5173\u914D\u7F6E ############################ +proxy.server.tcp.enabled=true +proxy.server.tcp.port=10000 +proxy.server.tcp.readerIdleSeconds=120 +proxy.server.tcp.writerIdleSeconds=120 +proxy.server.tcp.allIdleSeconds=120 +proxy.server.tcp.clientMaxNum=10000 + +#\u6D88\u606F\u4E0B\u53D1\u5931\u8D25 \u6807\u8BB0\u5BA2\u6237\u7AEF\u9694\u79BB\u65F6\u95F4 +proxy.server.tcp.pushFailIsolateTimeInMills=30000 + +#rebalance +proxy.server.tcp.RebalanceIntervalInMills=30000 + +#\u5BA2\u6237\u7AEFsession\u8FC7\u671F\u65F6\u95F4 +proxy.server.session.expiredInMills=60000 + +#flow control,\u5206global\u7EA7\u522B\u548Csession\u7EA7\u522B +proxy.server.tcp.msgReqnumPerSecond=15000 +proxy.server.session.upstreamBufferSize=20 +proxy.server.session.downstreamUnackSize=100 + +#\u5168\u5C40\u8C03\u5EA6\u5668\u7EBF\u7A0B\u4E2A\u6570 +proxy.server.global.scheduler=5 +proxy.server.tcp.traceLogExecutorPoolSize=5 +proxy.server.tcp.taskHandleExecutorPoolSize=8 + +#retry +proxy.server.retry.pushRetryTimes=3 +proxy.server.retry.pushRetryDelayInMills=500 +proxy.server.retry.pushRetryQueueSize=10000 + +#admin +proxy.server.admin.http.port=10106 + +#registry +proxy.server.registry.registerIntervalInMills=10000 +proxy.server.registry.fetchRegistryAddrIntervalInMills=20000 + +#auto-ack +proxy.server.defibus.client.comsumeTimeoutInMin=5 \ No newline at end of file diff --git a/eventmesh-runtime/src/main/java/com/webank/runtime/configuration/PropInit.java b/eventmesh-runtime/src/main/java/com/webank/runtime/configuration/PropInit.java new file mode 100644 index 0000000000..8428e79e7f --- /dev/null +++ b/eventmesh-runtime/src/main/java/com/webank/runtime/configuration/PropInit.java @@ -0,0 +1,9 @@ +package com.webank.runtime.configuration; + +import io.openmessaging.KeyValue; + +public interface PropInit { + + KeyValue initProp(); + +} diff --git a/eventmesh-runtime/src/main/java/com/webank/runtime/domain/BytesMessageImpl.java b/eventmesh-runtime/src/main/java/com/webank/runtime/domain/BytesMessageImpl.java new file mode 100644 index 0000000000..95dbec9003 --- /dev/null +++ b/eventmesh-runtime/src/main/java/com/webank/runtime/domain/BytesMessageImpl.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 com.webank.runtime.domain; + +import io.openmessaging.BytesMessage; +import io.openmessaging.KeyValue; +import io.openmessaging.Message; +import io.openmessaging.OMS; +import io.openmessaging.exception.OMSMessageFormatException; +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class BytesMessageImpl implements BytesMessage { + private KeyValue sysHeaders; + private KeyValue userHeaders; + private byte[] body; + + public BytesMessageImpl() { + this.sysHeaders = OMS.newKeyValue(); + this.userHeaders = OMS.newKeyValue(); + } + + @Override + public T getBody(Class type) throws OMSMessageFormatException { + if (type == byte[].class) { + return (T)body; + } + + throw new OMSMessageFormatException("", "Cannot assign byte[] to " + type.getName()); + } + + @Override + public BytesMessage setBody(final byte[] body) { + this.body = body; + return this; + } + + @Override + public KeyValue sysHeaders() { + return sysHeaders; + } + + @Override + public KeyValue userHeaders() { + return userHeaders; + } + + @Override + public Message putSysHeaders(String key, int value) { + sysHeaders.put(key, value); + return this; + } + + @Override + public Message putSysHeaders(String key, long value) { + sysHeaders.put(key, value); + return this; + } + + @Override + public Message putSysHeaders(String key, double value) { + sysHeaders.put(key, value); + return this; + } + + @Override + public Message putSysHeaders(String key, String value) { + sysHeaders.put(key, value); + return this; + } + + @Override + public Message putUserHeaders(String key, int value) { + userHeaders.put(key, value); + return this; + } + + @Override + public Message putUserHeaders(String key, long value) { + userHeaders.put(key, value); + return this; + } + + @Override + public Message putUserHeaders(String key, double value) { + userHeaders.put(key, value); + return this; + } + + @Override + public Message putUserHeaders(String key, String value) { + userHeaders.put(key, value); + return this; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/eventmesh-runtime/src/main/java/com/webank/runtime/domain/ConsumeRequest.java b/eventmesh-runtime/src/main/java/com/webank/runtime/domain/ConsumeRequest.java new file mode 100644 index 0000000000..3b0e84aa2d --- /dev/null +++ b/eventmesh-runtime/src/main/java/com/webank/runtime/domain/ConsumeRequest.java @@ -0,0 +1,55 @@ +/* + * 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 com.webank.runtime.domain; + +import org.apache.rocketmq.client.impl.consumer.ProcessQueue; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; + +public class ConsumeRequest { + private final MessageExt messageExt; + private final MessageQueue messageQueue; + private final ProcessQueue processQueue; + private long startConsumeTimeMillis; + + public ConsumeRequest(final MessageExt messageExt, final MessageQueue messageQueue, + final ProcessQueue processQueue) { + this.messageExt = messageExt; + this.messageQueue = messageQueue; + this.processQueue = processQueue; + } + + public MessageExt getMessageExt() { + return messageExt; + } + + public MessageQueue getMessageQueue() { + return messageQueue; + } + + public ProcessQueue getProcessQueue() { + return processQueue; + } + + public long getStartConsumeTimeMillis() { + return startConsumeTimeMillis; + } + + public void setStartConsumeTimeMillis(final long startConsumeTimeMillis) { + this.startConsumeTimeMillis = startConsumeTimeMillis; + } +} diff --git a/eventmesh-runtime/src/main/java/com/webank/runtime/domain/NonStandardKeys.java b/eventmesh-runtime/src/main/java/com/webank/runtime/domain/NonStandardKeys.java new file mode 100644 index 0000000000..4ca3a0c32a --- /dev/null +++ b/eventmesh-runtime/src/main/java/com/webank/runtime/domain/NonStandardKeys.java @@ -0,0 +1,30 @@ +/* + * 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 com.webank.runtime.domain; + +public interface NonStandardKeys { + String CONSUMER_GROUP = "rmq.consumer.group"; + String PRODUCER_GROUP = "rmq.producer.group"; + String MAX_REDELIVERY_TIMES = "rmq.max.redelivery.times"; + String MESSAGE_CONSUME_TIMEOUT = "rmq.message.consume.timeout"; + String MAX_CONSUME_THREAD_NUMS = "rmq.max.consume.thread.nums"; + String MIN_CONSUME_THREAD_NUMS = "rmq.min.consume.thread.nums"; + String MESSAGE_CONSUME_STATUS = "rmq.message.consume.status"; + String MESSAGE_DESTINATION = "rmq.message.destination"; + String PULL_MESSAGE_BATCH_NUMS = "rmq.pull.message.batch.nums"; + String PULL_MESSAGE_CACHE_CAPACITY = "rmq.pull.message.cache.capacity"; +} diff --git a/eventmesh-runtime/src/main/java/com/webank/runtime/domain/RocketMQConstants.java b/eventmesh-runtime/src/main/java/com/webank/runtime/domain/RocketMQConstants.java new file mode 100644 index 0000000000..68574a0436 --- /dev/null +++ b/eventmesh-runtime/src/main/java/com/webank/runtime/domain/RocketMQConstants.java @@ -0,0 +1,26 @@ +/* + * 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 com.webank.runtime.domain; + +public interface RocketMQConstants { + + /** + * Key of scheduled message delivery time + */ + String START_DELIVER_TIME = "__STARTDELIVERTIME"; + +} diff --git a/eventmesh-runtime/src/main/java/com/webank/runtime/domain/SendResultImpl.java b/eventmesh-runtime/src/main/java/com/webank/runtime/domain/SendResultImpl.java new file mode 100644 index 0000000000..fb50680e21 --- /dev/null +++ b/eventmesh-runtime/src/main/java/com/webank/runtime/domain/SendResultImpl.java @@ -0,0 +1,39 @@ +/* + * 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 com.webank.runtime.domain; + +import io.openmessaging.KeyValue; +import io.openmessaging.producer.SendResult; + +public class SendResultImpl implements SendResult { + private String messageId; + private KeyValue properties; + + public SendResultImpl(final String messageId, final KeyValue properties) { + this.messageId = messageId; + this.properties = properties; + } + + @Override + public String messageId() { + return messageId; + } + + public KeyValue properties() { + return properties; + } +} diff --git a/eventmesh-runtime/src/main/java/com/webank/runtime/util/OMSUtil.java b/eventmesh-runtime/src/main/java/com/webank/runtime/util/OMSUtil.java new file mode 100644 index 0000000000..2e6873d61f --- /dev/null +++ b/eventmesh-runtime/src/main/java/com/webank/runtime/util/OMSUtil.java @@ -0,0 +1,181 @@ +/* + * 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 com.webank.runtime.util; + +import com.webank.runtime.domain.BytesMessageImpl; +import com.webank.runtime.domain.RocketMQConstants; +import com.webank.runtime.domain.SendResultImpl; +import io.openmessaging.BytesMessage; +import io.openmessaging.KeyValue; +import io.openmessaging.Message.BuiltinKeys; +import io.openmessaging.OMS; +import io.openmessaging.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.UtilAll; +import org.apache.rocketmq.common.message.MessageAccessor; + +import java.lang.reflect.Field; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +public class OMSUtil { + + /** + * Builds a OMS client instance name. + * + * @return a unique instance name + */ + public static String buildInstanceName() { + return Integer.toString(UtilAll.getPid()) + "%OpenMessaging" + "%" + System.nanoTime(); + } + + public static org.apache.rocketmq.common.message.Message msgConvert(BytesMessage omsMessage) { + org.apache.rocketmq.common.message.Message rmqMessage = new org.apache.rocketmq.common.message.Message(); + rmqMessage.setBody(omsMessage.getBody(byte[].class)); + + KeyValue sysHeaders = omsMessage.sysHeaders(); + KeyValue userHeaders = omsMessage.userHeaders(); + + //All destinations in RocketMQ use Topic + rmqMessage.setTopic(sysHeaders.getString(BuiltinKeys.DESTINATION)); + + if (sysHeaders.containsKey(BuiltinKeys.START_TIME)) { + long deliverTime = sysHeaders.getLong(BuiltinKeys.START_TIME, 0); + if (deliverTime > 0) { + rmqMessage.putUserProperty(RocketMQConstants.START_DELIVER_TIME, String.valueOf(deliverTime)); + } + } + + for (String key : userHeaders.keySet()) { + MessageAccessor.putProperty(rmqMessage, key, userHeaders.getString(key)); + } + + //System headers has a high priority + for (String key : sysHeaders.keySet()) { + MessageAccessor.putProperty(rmqMessage, key, sysHeaders.getString(key)); + } + + return rmqMessage; + } + + public static BytesMessage msgConvert(org.apache.rocketmq.common.message.MessageExt rmqMsg) { + BytesMessage omsMsg = new BytesMessageImpl(); + omsMsg.setBody(rmqMsg.getBody()); + + KeyValue headers = omsMsg.sysHeaders(); + KeyValue properties = omsMsg.userHeaders(); + + final Set> entries = rmqMsg.getProperties().entrySet(); + + for (final Map.Entry entry : entries) { + if (isOMSHeader(entry.getKey())) { + headers.put(entry.getKey(), entry.getValue()); + } else { + properties.put(entry.getKey(), entry.getValue()); + } + } + + omsMsg.putSysHeaders(BuiltinKeys.MESSAGE_ID, rmqMsg.getMsgId()); + + omsMsg.putSysHeaders(BuiltinKeys.DESTINATION, rmqMsg.getTopic()); + + omsMsg.putSysHeaders(BuiltinKeys.SEARCH_KEYS, rmqMsg.getKeys()); + omsMsg.putSysHeaders(BuiltinKeys.BORN_HOST, String.valueOf(rmqMsg.getBornHost())); + omsMsg.putSysHeaders(BuiltinKeys.BORN_TIMESTAMP, rmqMsg.getBornTimestamp()); + omsMsg.putSysHeaders(BuiltinKeys.STORE_HOST, String.valueOf(rmqMsg.getStoreHost())); + omsMsg.putSysHeaders(BuiltinKeys.STORE_TIMESTAMP, rmqMsg.getStoreTimestamp()); + return omsMsg; + } + + public static boolean isOMSHeader(String value) { + for (Field field : BuiltinKeys.class.getDeclaredFields()) { + try { + if (field.get(BuiltinKeys.class).equals(value)) { + return true; + } + } catch (IllegalAccessException e) { + return false; + } + } + return false; + } + + /** + * Convert a RocketMQ SEND_OK SendResult instance to a OMS SendResult. + */ + public static SendResult sendResultConvert(org.apache.rocketmq.client.producer.SendResult rmqResult) { + assert rmqResult.getSendStatus().equals(SendStatus.SEND_OK); + return new SendResultImpl(rmqResult.getMsgId(), OMS.newKeyValue()); + } + + public static KeyValue buildKeyValue(KeyValue... keyValues) { + KeyValue keyValue = OMS.newKeyValue(); + for (KeyValue properties : keyValues) { + for (String key : properties.keySet()) { + keyValue.put(key, properties.getString(key)); + } + } + return keyValue; + } + + /** + * Returns an iterator that cycles indefinitely over the elements of {@code Iterable}. + */ + public static Iterator cycle(final Iterable iterable) { + return new Iterator() { + Iterator iterator = new Iterator() { + @Override + public synchronized boolean hasNext() { + return false; + } + + @Override + public synchronized T next() { + throw new NoSuchElementException(); + } + + @Override + public synchronized void remove() { + //Ignore + } + }; + + @Override + public synchronized boolean hasNext() { + return iterator.hasNext() || iterable.iterator().hasNext(); + } + + @Override + public synchronized T next() { + if (!iterator.hasNext()) { + iterator = iterable.iterator(); + if (!iterator.hasNext()) { + throw new NoSuchElementException(); + } + } + return iterator.next(); + } + + @Override + public synchronized void remove() { + iterator.remove(); + } + }; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyContext.java b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyContext.java new file mode 100644 index 0000000000..de8c44fef9 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyContext.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyContext.java +package org.apache.rocketmq.client.impl.consumer; +======== +package com.webank.runtime.patch; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/patch/ProxyConsumeConcurrentlyContext.java + +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.common.message.MessageQueue; + +public class ConsumeMessageConcurrentlyContext extends ConsumeConcurrentlyContext { + private final ProcessQueue processQueue; + private boolean manualAck = true; + + public ConsumeMessageConcurrentlyContext(MessageQueue messageQueue, ProcessQueue processQueue) { + super(messageQueue); + this.processQueue = processQueue; + } + + public ProcessQueue getProcessQueue() { + return processQueue; + } + + public boolean isManualAck() { + return manualAck; + } + + public void setManualAck(boolean manualAck) { + this.manualAck = manualAck; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java new file mode 100644 index 0000000000..a2b96774c0 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java @@ -0,0 +1,521 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.client.impl.consumer; + +import cn.webank.emesher.threads.ThreadPoolHelper; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.ConsumeReturnType; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.consumer.store.ReadOffsetType; +import org.apache.rocketmq.client.hook.ConsumeMessageContext; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.client.stat.ConsumerStatsManager; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.body.CMResult; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.Semaphore; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class ConsumeMessageConcurrentlyService implements ConsumeMessageService { + private static final InternalLogger log = ClientLogger.getLog(); + private final DefaultMQPushConsumerImpl defaultMQPushConsumerImpl; + private final DefaultMQPushConsumer defaultMQPushConsumer; + private final MessageListenerConcurrently messageListener; + private ThreadPoolExecutor consumeExecutor; + private final String consumerGroup; + + private final ScheduledExecutorService scheduledExecutorService; + private final ScheduledExecutorService cleanExpireMsgExecutors; + + private final Semaphore semaphore; + + public ConsumeMessageConcurrentlyService(DefaultMQPushConsumerImpl defaultMQPushConsumerImpl, + MessageListenerConcurrently messageListener) { + this.defaultMQPushConsumerImpl = defaultMQPushConsumerImpl; + this.messageListener = messageListener; + + this.defaultMQPushConsumer = this.defaultMQPushConsumerImpl.getDefaultMQPushConsumer(); + this.consumerGroup = this.defaultMQPushConsumer.getConsumerGroup(); + + this.consumeExecutor = ThreadPoolHelper.getConsumeMessageExecutor(); + + semaphore = new Semaphore(consumeExecutor.getQueue().remainingCapacity(), true); + + this.scheduledExecutorService = ThreadPoolHelper.getConsumeMessageScheduledThread(); + this.cleanExpireMsgExecutors = ThreadPoolHelper.getCleanExpireMsgScheduledThread(); + } + + public void start() { + if (this.defaultMQPushConsumer.getConsumeTimeout() > 0) { + this.cleanExpireMsgExecutors.scheduleAtFixedRate(new Runnable() { + + @Override + public void run() { + try { + cleanExpireMsg(); + } catch (Exception e) { + log.warn("cleanExpireMsg ", e); + } + } + + }, this.defaultMQPushConsumer.getConsumeTimeout(), this.defaultMQPushConsumer.getConsumeTimeout(), TimeUnit.MINUTES); + } + } + + public void shutdown() { + this.scheduledExecutorService.shutdown(); + this.consumeExecutor.shutdown(); + while (!consumeExecutor.isTerminated()) { + try { + consumeExecutor.awaitTermination(50, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + log.warn("", e); + } + } + this.cleanExpireMsgExecutors.shutdown(); + } + + public ThreadPoolExecutor getConsumeExecutor() { + return consumeExecutor; + } + + public void setConsumeExecutor(ThreadPoolExecutor consumeExecutor) { + this.consumeExecutor = consumeExecutor; + } + + @Override + public void updateCorePoolSize(int corePoolSize) { + } + + @Override + public void incCorePoolSize() { + } + + @Override + public void decCorePoolSize() { + } + + @Override + public int getCorePoolSize() { + return this.consumeExecutor.getCorePoolSize(); + } + + @Override + public ConsumeMessageDirectlyResult consumeMessageDirectly(MessageExt msg, String brokerName) { + ConsumeMessageDirectlyResult result = new ConsumeMessageDirectlyResult(); + result.setOrder(false); + result.setAutoCommit(true); + + List msgs = new ArrayList(); + msgs.add(msg); + MessageQueue mq = new MessageQueue(); + mq.setBrokerName(brokerName); + mq.setTopic(msg.getTopic()); + mq.setQueueId(msg.getQueueId()); + ProcessQueue pq = new ProcessQueue(); + ConsumeMessageConcurrentlyContext context = new ConsumeMessageConcurrentlyContext(mq, pq); + + this.resetRetryTopic(msgs); + + final long beginTime = System.currentTimeMillis(); + + log.info("consumeMessageDirectly receive new message: {}", msg); + + try { + ConsumeConcurrentlyStatus status = this.messageListener.consumeMessage(msgs, context); + if (status != null) { + switch (status) { + case CONSUME_SUCCESS: + result.setConsumeResult(CMResult.CR_SUCCESS); + break; + case RECONSUME_LATER: + result.setConsumeResult(CMResult.CR_LATER); + break; + default: + break; + } + } else { + result.setConsumeResult(CMResult.CR_RETURN_NULL); + } + } catch (Throwable e) { + result.setConsumeResult(CMResult.CR_THROW_EXCEPTION); + result.setRemark(RemotingHelper.exceptionSimpleDesc(e)); + + log.warn(String.format("consumeMessageDirectly failed: %s Group: %s Msgs: %s MQ: %s", // + RemotingHelper.exceptionSimpleDesc(e), // + ConsumeMessageConcurrentlyService.this.consumerGroup, // + msgs, // + mq), e); + } + + result.setSpentTimeMills(System.currentTimeMillis() - beginTime); + + log.info("consumeMessageDirectly Result: {}", result); + + return result; + } + + @Override + public void submitConsumeRequest( + final List msgs, + final ProcessQueue processQueue, + final MessageQueue messageQueue, + final boolean dispatchToConsume) { + final int consumeBatchSize = this.defaultMQPushConsumer.getConsumeMessageBatchMaxSize(); + if (msgs.size() <= consumeBatchSize) { + ConsumeRequest consumeRequest = new ConsumeRequest(msgs, processQueue, messageQueue); + try { + log.debug("acquire semaphore, queued size {}, availablePermits {}", semaphore.getQueueLength(), semaphore.availablePermits()); + semaphore.acquire(); + this.consumeExecutor.submit(consumeRequest); + } catch (RejectedExecutionException e) { + this.submitConsumeRequestLater(consumeRequest); + } catch (InterruptedException e) { + log.warn("acquire semaphore fail when submit consumeRequest. {} {}", e.getMessage(), msgs); + } + } else { + for (int total = 0; total < msgs.size(); ) { + List msgThis = new ArrayList(consumeBatchSize); + for (int i = 0; i < consumeBatchSize; i++, total++) { + if (total < msgs.size()) { + msgThis.add(msgs.get(total)); + } else { + break; + } + } + + ConsumeRequest consumeRequest = new ConsumeRequest(msgThis, processQueue, messageQueue); + try { + log.debug("acquire semaphore, queued size {}, availablePermits {}", semaphore.getQueueLength(), semaphore.availablePermits()); + semaphore.acquire(); + this.consumeExecutor.submit(consumeRequest); + } catch (RejectedExecutionException e) { + for (; total < msgs.size(); total++) { + msgThis.add(msgs.get(total)); + } + + this.submitConsumeRequestLater(consumeRequest); + } catch (InterruptedException e) { + log.warn("acquire semaphore fail when submit consumeRequest. {} {}", e.getMessage(), msgs); + } + } + } + } + + public void resetRetryTopic(final List msgs) { + final String groupTopic = MixAll.getRetryTopic(consumerGroup); + for (MessageExt msg : msgs) { + String retryTopic = msg.getProperty(MessageConst.PROPERTY_RETRY_TOPIC); + if (retryTopic != null && groupTopic.equals(msg.getTopic())) { + msg.setTopic(retryTopic); + } + } + } + + private void cleanExpireMsg() { + Iterator> it = + this.defaultMQPushConsumerImpl.getRebalanceImpl().getProcessQueueTable().entrySet().iterator(); + while (it.hasNext()) { + Map.Entry next = it.next(); + ProcessQueue pq = next.getValue(); + pq.cleanExpiredMsg(this.defaultMQPushConsumer); + } + } + + public void processConsumeResult( + final ConsumeConcurrentlyStatus status, + final ConsumeMessageConcurrentlyContext context, + final ConsumeRequest consumeRequest + ) { + int ackIndex = context.getAckIndex(); + + if (consumeRequest.getMsgs().isEmpty()) + return; + + switch (status) { + case CONSUME_SUCCESS: + if (ackIndex >= consumeRequest.getMsgs().size()) { + ackIndex = consumeRequest.getMsgs().size() - 1; + } + int ok = ackIndex + 1; + int failed = consumeRequest.getMsgs().size() - ok; + this.getConsumerStatsManager().incConsumeOKTPS(consumerGroup, consumeRequest.getMessageQueue().getTopic(), ok); + this.getConsumerStatsManager().incConsumeFailedTPS(consumerGroup, consumeRequest.getMessageQueue().getTopic(), failed); + break; + case RECONSUME_LATER: + ackIndex = -1; + this.getConsumerStatsManager().incConsumeFailedTPS(consumerGroup, consumeRequest.getMessageQueue().getTopic(), + consumeRequest.getMsgs().size()); + break; + default: + break; + } + + switch (this.defaultMQPushConsumer.getMessageModel()) { + case BROADCASTING: + for (int i = ackIndex + 1; i < consumeRequest.getMsgs().size(); i++) { + MessageExt msg = consumeRequest.getMsgs().get(i); + log.warn("BROADCASTING, the message consume failed, drop it, {}", msg.toString()); + } + break; + case CLUSTERING: + List msgBackFailed = new ArrayList(consumeRequest.getMsgs().size()); + for (int i = ackIndex + 1; i < consumeRequest.getMsgs().size(); i++) { + MessageExt msg = consumeRequest.getMsgs().get(i); + boolean result = this.sendMessageBack(msg, context); + if (!result) { + msg.setReconsumeTimes(msg.getReconsumeTimes() + 1); + msgBackFailed.add(msg); + } + } + + if (!msgBackFailed.isEmpty()) { + consumeRequest.getMsgs().removeAll(msgBackFailed); + + this.submitConsumeRequestLater(msgBackFailed, consumeRequest.getProcessQueue(), consumeRequest.getMessageQueue()); + } + break; + default: + break; + } + if (!context.isManualAck()) { + updateOffset(consumeRequest.getMsgs(), context); + } + } + + public void updateOffset(List msgs, ConsumeMessageConcurrentlyContext context) { + for (MessageExt m : msgs) { + log.debug("update offset, msg: {} {} {}", m.getTopic(), m.getQueueId(), m.getQueueOffset()); + } + MessageQueue messageQueue = context.getMessageQueue(); + ProcessQueue processQueue = context.getProcessQueue(); + long offset = processQueue.removeMessage(msgs); + if (offset >= 0) { + log.debug("update offset={}", offset); + this.defaultMQPushConsumerImpl.getOffsetStore().updateOffset(messageQueue, offset, true); + } + + boolean isMqInTable = defaultMQPushConsumerImpl.getRebalanceImpl().getProcessQueueTable().containsKey(messageQueue); + boolean isTopicStillSub = defaultMQPushConsumerImpl.getRebalanceImpl().getSubscriptionInner().containsKey(messageQueue.getTopic()); + if ((!isMqInTable || !isTopicStillSub || processQueue.isDropped())/* && pq.getMsgTreeMap().isEmpty()*/) { + long starttime = System.currentTimeMillis(); + defaultMQPushConsumerImpl.getOffsetStore().persist(messageQueue); + long cost = System.currentTimeMillis() - starttime; + log.info("[persist]persist when handle last message. clientId:{} {}, ackOffset:{}, lastPullTime:{}, persist cost {} ms. isMqInProcessQueueTable:{}, isTopicStillSub:{}, isDrop:{}", + defaultMQPushConsumerImpl.getmQClientFactory().getClientId(), + messageQueue, defaultMQPushConsumerImpl.getOffsetStore().readOffset(messageQueue, ReadOffsetType.READ_FROM_MEMORY), + processQueue.getLastPullTimestamp(), cost, + isMqInTable, isTopicStillSub, processQueue.isDropped()); + } + } + + public ConsumerStatsManager getConsumerStatsManager() { + return this.defaultMQPushConsumerImpl.getConsumerStatsManager(); + } + + public boolean sendMessageBack(final MessageExt msg, final ConsumeConcurrentlyContext context) { + int delayLevel = context.getDelayLevelWhenNextConsume(); + + try { + this.defaultMQPushConsumerImpl.sendMessageBack(msg, delayLevel, context.getMessageQueue().getBrokerName()); + return true; + } catch (Exception e) { + log.warn("sendMessageBack except, group: " + this.consumerGroup + " msg: " + msg.toString(), e); + } + + return false; + } + + private void submitConsumeRequestLater( + final List msgs, + final ProcessQueue processQueue, + final MessageQueue messageQueue + ) { + + this.scheduledExecutorService.schedule(new Runnable() { + + @Override + public void run() { + ConsumeMessageConcurrentlyService.this.submitConsumeRequest(msgs, processQueue, messageQueue, true); + } + }, 5000, TimeUnit.MILLISECONDS); + } + + private void submitConsumeRequestLater(final ConsumeRequest consumeRequest + ) { + final int times = defaultMQPushConsumerImpl.getDefaultMQPushConsumer().getMaxReconsumeTimes(); + log.warn("rejected by thread pool, try resubmit {} times, consumerGroup:{}", times, defaultMQPushConsumerImpl.getDefaultMQPushConsumer().getConsumerGroup()); + this.scheduledExecutorService.schedule(new Runnable() { + + @Override + public void run() { + boolean success = false; + for (int i = 0; i < times; i++) { + try { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + ConsumeMessageConcurrentlyService.this.consumeExecutor.submit(consumeRequest); + success = true; + break; + } catch (RejectedExecutionException e) { + + } + } + if (!success) { + for (MessageExt messageExt : consumeRequest.getMsgs()) { + log.warn("discard rejected messages {} after retry {} times", messageExt, times); + } + consumeRequest.getProcessQueue().removeMessage(consumeRequest.getMsgs()); + } + } + }, 1000, TimeUnit.MILLISECONDS); + } + + class ConsumeRequest implements Runnable { + private final List msgs; + private final ProcessQueue processQueue; + private final MessageQueue messageQueue; + + public ConsumeRequest(List msgs, ProcessQueue processQueue, MessageQueue messageQueue) { + this.msgs = msgs; + this.processQueue = processQueue; + this.messageQueue = messageQueue; + } + + public List getMsgs() { + return msgs; + } + + public ProcessQueue getProcessQueue() { + return processQueue; + } + + @Override + public void run() { + try { + if (this.processQueue.isDropped()) { + log.info("the message queue not be able to consume, because it's dropped. group={} {}", ConsumeMessageConcurrentlyService.this.consumerGroup, this.messageQueue); + for (MessageExt msg : msgs) { + log.debug("discard message because process queue is dropped. {}", msg); + } + return; + } + + MessageListenerConcurrently listener = ConsumeMessageConcurrentlyService.this.messageListener; + ConsumeMessageConcurrentlyContext context = new ConsumeMessageConcurrentlyContext(messageQueue, processQueue); + ConsumeConcurrentlyStatus status = null; + + ConsumeMessageContext consumeMessageContext = null; + if (ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.hasHook()) { + consumeMessageContext = new ConsumeMessageContext(); + consumeMessageContext.setConsumerGroup(defaultMQPushConsumer.getConsumerGroup()); + consumeMessageContext.setProps(new HashMap()); + consumeMessageContext.setMq(messageQueue); + consumeMessageContext.setMsgList(msgs); + consumeMessageContext.setSuccess(false); + ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.executeHookBefore(consumeMessageContext); + } + + long beginTimestamp = System.currentTimeMillis(); + boolean hasException = false; + ConsumeReturnType returnType = ConsumeReturnType.SUCCESS; + try { + ConsumeMessageConcurrentlyService.this.resetRetryTopic(msgs); + if (msgs != null && !msgs.isEmpty()) { + for (MessageExt msg : msgs) { + MessageAccessor.setConsumeStartTimeStamp(msg, String.valueOf(System.currentTimeMillis())); + } + } + status = listener.consumeMessage(Collections.unmodifiableList(msgs), context); + } catch (Throwable e) { + log.warn("consumeMessage failed: {} Group: {} Msgs: {} MQ: {}", + RemotingHelper.exceptionSimpleDesc(e), // + ConsumeMessageConcurrentlyService.this.consumerGroup, + msgs, + messageQueue); + hasException = true; + } + long consumeRT = System.currentTimeMillis() - beginTimestamp; + if (null == status) { + if (hasException) { + returnType = ConsumeReturnType.EXCEPTION; + } else { + returnType = ConsumeReturnType.RETURNNULL; + } + } else if (consumeRT >= defaultMQPushConsumer.getConsumeTimeout() * 60 * 1000) { + returnType = ConsumeReturnType.TIME_OUT; + } else if (ConsumeConcurrentlyStatus.RECONSUME_LATER == status) { + returnType = ConsumeReturnType.FAILED; + } else if (ConsumeConcurrentlyStatus.CONSUME_SUCCESS == status) { + returnType = ConsumeReturnType.SUCCESS; + } + + if (ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.hasHook()) { + consumeMessageContext.getProps().put(MixAll.CONSUME_CONTEXT_TYPE, returnType.name()); + } + + if (null == status) { + log.warn("consumeMessage return null, Group: {} Msgs: {} MQ: {}", + ConsumeMessageConcurrentlyService.this.consumerGroup, + msgs, + messageQueue); + status = ConsumeConcurrentlyStatus.RECONSUME_LATER; + } + + if (ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.hasHook()) { + consumeMessageContext.setStatus(status.toString()); + consumeMessageContext.setSuccess(ConsumeConcurrentlyStatus.CONSUME_SUCCESS == status); + ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.executeHookAfter(consumeMessageContext); + } + + ConsumeMessageConcurrentlyService.this.getConsumerStatsManager() + .incConsumeRT(ConsumeMessageConcurrentlyService.this.consumerGroup, messageQueue.getTopic(), consumeRT); + + + ConsumeMessageConcurrentlyService.this.processConsumeResult(status, context, this); + } + finally { + semaphore.release(); + } + } + + public MessageQueue getMessageQueue() { + return messageQueue; + } + + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ProxyConsumeConcurrentlyStatus.java b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ProxyConsumeConcurrentlyStatus.java new file mode 100644 index 0000000000..40c7e2bc96 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ProxyConsumeConcurrentlyStatus.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ProxyConsumeConcurrentlyStatus.java +package org.apache.rocketmq.client.impl.consumer; +======== +package com.webank.runtime.patch; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/patch/ProxyConsumeConcurrentlyStatus.java + +public enum ProxyConsumeConcurrentlyStatus { + /** + * Success consumption + */ + CONSUME_SUCCESS, + /** + * Failure consumption,later try to consume + */ + RECONSUME_LATER, + /** + * Success consumption but ack later manually + */ + CONSUME_FINISH; +} diff --git a/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ProxyMessageListenerConcurrentlyOnce.java b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ProxyMessageListenerConcurrentlyOnce.java new file mode 100644 index 0000000000..10e619da7c --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/ProxyMessageListenerConcurrentlyOnce.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.client.impl.consumer; + +import cn.webank.defibus.consumer.DeFiBusMessageListenerConcurrentlyOnce; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class ProxyMessageListenerConcurrentlyOnce extends DeFiBusMessageListenerConcurrentlyOnce { + private static final Logger LOG = LoggerFactory.getLogger(ProxyMessageListenerConcurrentlyOnce.class); + + @Override + public ConsumeConcurrentlyStatus handleMessage(MessageExt msg, ConsumeConcurrentlyContext context) { + ProxyConsumeConcurrentlyStatus status = null; + ConsumeMessageConcurrentlyContext consumeContext = (ConsumeMessageConcurrentlyContext)context; + try { + status = handleMessage(msg, consumeContext); + switch (status) { + case CONSUME_SUCCESS: + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + case RECONSUME_LATER: + return ConsumeConcurrentlyStatus.RECONSUME_LATER; + case CONSUME_FINISH: + consumeContext.setManualAck(true); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + } catch (Throwable e) { + LOG.info("handleMessage fail", e); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + return null; + } + + public abstract ProxyConsumeConcurrentlyStatus handleMessage(MessageExt msg, ConsumeMessageConcurrentlyContext context); +} diff --git a/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/PullMessageService.java b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/PullMessageService.java new file mode 100644 index 0000000000..9fce0eaf73 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/PullMessageService.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.client.impl.consumer; + +import cn.webank.emesher.threads.ThreadPoolHelper; +import org.apache.rocketmq.client.impl.factory.MQClientInstance; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.common.ServiceThread; +import org.apache.rocketmq.logging.InternalLogger; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class PullMessageService extends ServiceThread { + private final InternalLogger log = ClientLogger.getLog(); + private final MQClientInstance mQClientFactory; + private final ScheduledExecutorService scheduledExecutorService = ThreadPoolHelper + .getPullMessageServiceScheduledThread(); + private final ScheduledExecutorService retryScheduledExecutorService = ThreadPoolHelper + .getPullMessageRetryServiceScheduledThread(); + private final ConcurrentHashMap isolatedBroker = new ConcurrentHashMap<>(); + private long ISOLATE_THRESHOLD = 500; + private long ISOLATE_TIMEOUT = 5 * 60 * 1000; + + public PullMessageService(MQClientInstance mQClientFactory) { + super(true); + this.mQClientFactory = mQClientFactory; + } + + public void executePullRequestLater(final PullRequest pullRequest, final long timeDelay) { + if (!isStopped()) { + this.scheduledExecutorService.schedule(new Runnable() { + //use this to identify anonymous inner class + private static final String tag = "ExecutePullRequestLater"; + + @Override + public void run() { + PullMessageService.this.executePullRequestImmediately(pullRequest); + } + }, timeDelay, TimeUnit.MILLISECONDS); + } else { + log.warn("PullMessageServiceScheduledThread has shutdown"); + } + } + + public void executePullRequestImmediately(final PullRequest pullRequest) { + if (this.isStopped() || pullRequest == null) return; + this.scheduledExecutorService.execute(new Runnable() { + //use this to identify anonymous inner class + private static final String tag = "ExecutePullRequestImmediately"; + + @Override + public void run() { + if (!PullMessageService.this.isStopped()) { + PullMessageService.this.pullMessage(pullRequest); + } + } + }); + } + + public void executeTaskLater(final Runnable r, final long timeDelay) { + if (!isStopped()) { + this.scheduledExecutorService.schedule(r, timeDelay, TimeUnit.MILLISECONDS); + } else { + log.warn("PullMessageServiceScheduledThread has shutdown"); + } + } + + public ScheduledExecutorService getScheduledExecutorService() { + return scheduledExecutorService; + } + + public void isolateBroker(String brokerName){ + log.info("isolate broker for slow pull message, {}", brokerName); + isolatedBroker.put(brokerName, System.currentTimeMillis()); + } + + public void removeIsolateBroker(String brokerName){ + Long val = isolatedBroker.remove(brokerName); + log.info("remove isolated broker, brokerName: {} isolate time: {}", brokerName, val); + } + + public boolean isBrokerAvailable(String brokerName){ + boolean brokerIsolated = isolatedBroker.containsKey(brokerName); + if (brokerIsolated){ + boolean isolatedTimeout = System.currentTimeMillis() - isolatedBroker.get(brokerName) > ISOLATE_TIMEOUT; + if (isolatedTimeout) { + removeIsolateBroker(brokerName); + return true; + } + else { + return false; + } + } + else { + return true; + } + } + + private void pullMessage(final PullRequest pullRequest) { + boolean brokerAvailable = isBrokerAvailable(pullRequest.getMessageQueue().getBrokerName()); + if (brokerAvailable) { + final MQConsumerInner consumer = this.mQClientFactory.selectConsumer(pullRequest.getConsumerGroup()); + if (consumer != null) { + DefaultMQPushConsumerImpl impl = (DefaultMQPushConsumerImpl) consumer; + long beginPullRequestTime = System.currentTimeMillis(); + log.debug("begin Pull Message, {}", pullRequest); + impl.pullMessage(pullRequest); + long rt = System.currentTimeMillis() - beginPullRequestTime; + if (rt >= ISOLATE_THRESHOLD) { + this.isolateBroker(pullRequest.getMessageQueue().getBrokerName()); + } + } else { + log.warn("No matched consumer for the PullRequest {}, drop it", pullRequest); + } + } else { + pullMessageByRetryExecutor(pullRequest); + } + } + + private void pullMessageByRetryExecutor(final PullRequest pullRequest) { + if (this.isStopped() || pullRequest == null) return; + this.retryScheduledExecutorService.execute(new Runnable() { + private static final String tag = "RetryExecutePullRequestImmediately"; + + @Override + public void run() { + if (!PullMessageService.this.isStopped()) { + final MQConsumerInner consumer = mQClientFactory.selectConsumer(pullRequest.getConsumerGroup()); + if (consumer != null) { + final DefaultMQPushConsumerImpl impl = (DefaultMQPushConsumerImpl) consumer; + log.debug("begin Pull Message, {}", pullRequest); + impl.pullMessage(pullRequest); + } else { + log.warn("No matched consumer for the PullRequest {}, drop it", pullRequest); + } + } + } + }); + } + + @Override + public void start() { + log.debug("PullMessageServiceThread has been replaced with a thread pool."); + } + + @Override + public void run() { + /** expected never be called */ + throw new UnsupportedOperationException("proxy internal bug."); + } + + @Override + public void shutdown(boolean interrupt) { + scheduledExecutorService.shutdown(); + retryScheduledExecutorService.shutdown(); + } + + @Override + public String getServiceName() { + return PullMessageService.class.getSimpleName(); + } + + public void makeStop() { + super.makeStop(); + scheduledExecutorService.shutdown(); + retryScheduledExecutorService.shutdown(); + } + + public void stop(final boolean interrupt) { + shutdown(interrupt); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java new file mode 100644 index 0000000000..0256f5edb9 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java @@ -0,0 +1,525 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.client.impl.consumer; + +import cn.webank.emesher.threads.ThreadPoolHelper; +import org.apache.rocketmq.client.consumer.AllocateMessageQueueStrategy; +import org.apache.rocketmq.client.impl.FindBrokerResult; +import org.apache.rocketmq.client.impl.factory.MQClientInstance; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.common.CountDownLatch2; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.body.LockBatchRequestBody; +import org.apache.rocketmq.common.protocol.body.UnlockBatchRequestBody; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.logging.InternalLogger; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * Base class for rebalance algorithm + */ +public abstract class RebalanceImpl { + protected static final InternalLogger log = ClientLogger.getLog(); + protected final ConcurrentMap processQueueTable = new ConcurrentHashMap(64); + protected final ConcurrentMap> topicSubscribeInfoTable = + new ConcurrentHashMap>(); + protected final ConcurrentMap subscriptionInner = + new ConcurrentHashMap(); + protected String consumerGroup; + protected MessageModel messageModel; + protected AllocateMessageQueueStrategy allocateMessageQueueStrategy; + protected MQClientInstance mQClientFactory; + protected ExecutorService executorService = ThreadPoolHelper.getRebalanceImplExecutorService(); + + public RebalanceImpl(String consumerGroup, MessageModel messageModel, + AllocateMessageQueueStrategy allocateMessageQueueStrategy, + MQClientInstance mQClientFactory) { + this.consumerGroup = consumerGroup; + this.messageModel = messageModel; + this.allocateMessageQueueStrategy = allocateMessageQueueStrategy; + this.mQClientFactory = mQClientFactory; + } + + public void unlock(final MessageQueue mq, final boolean oneway) { + FindBrokerResult findBrokerResult = this.mQClientFactory.findBrokerAddressInSubscribe(mq.getBrokerName(), MixAll.MASTER_ID, true); + if (findBrokerResult != null) { + UnlockBatchRequestBody requestBody = new UnlockBatchRequestBody(); + requestBody.setConsumerGroup(this.consumerGroup); + requestBody.setClientId(this.mQClientFactory.getClientId()); + requestBody.getMqSet().add(mq); + + try { + this.mQClientFactory.getMQClientAPIImpl().unlockBatchMQ(findBrokerResult.getBrokerAddr(), requestBody, 1000, oneway); + log.warn("unlock messageQueue. group:{}, clientId:{}, mq:{}", + this.consumerGroup, + this.mQClientFactory.getClientId(), + mq); + } catch (Exception e) { + log.warn("unlockBatchMQ except, " + mq, e); + } + } + } + + public void unlockAll(final boolean oneway) { + HashMap> brokerMqs = this.buildProcessQueueTableByBrokerName(); + + for (final Map.Entry> entry : brokerMqs.entrySet()) { + final String brokerName = entry.getKey(); + final Set mqs = entry.getValue(); + + if (mqs.isEmpty()) + continue; + + FindBrokerResult findBrokerResult = this.mQClientFactory.findBrokerAddressInSubscribe(brokerName, MixAll.MASTER_ID, true); + if (findBrokerResult != null) { + UnlockBatchRequestBody requestBody = new UnlockBatchRequestBody(); + requestBody.setConsumerGroup(this.consumerGroup); + requestBody.setClientId(this.mQClientFactory.getClientId()); + requestBody.setMqSet(mqs); + + try { + this.mQClientFactory.getMQClientAPIImpl().unlockBatchMQ(findBrokerResult.getBrokerAddr(), requestBody, 1000, oneway); + + for (MessageQueue mq : mqs) { + ProcessQueue processQueue = this.processQueueTable.get(mq); + if (processQueue != null) { + processQueue.setLocked(false); + log.info("the message queue unlock OK, Group: {} {}", this.consumerGroup, mq); + } + } + } catch (Exception e) { + log.warn("unlockBatchMQ except, " + mqs, e); + } + } + } + } + + private HashMap> buildProcessQueueTableByBrokerName() { + HashMap> result = new HashMap>(); + for (MessageQueue mq : this.processQueueTable.keySet()) { + Set mqs = result.get(mq.getBrokerName()); + if (null == mqs) { + mqs = new HashSet(); + result.put(mq.getBrokerName(), mqs); + } + + mqs.add(mq); + } + + return result; + } + + public boolean lock(final MessageQueue mq) { + FindBrokerResult findBrokerResult = this.mQClientFactory.findBrokerAddressInSubscribe(mq.getBrokerName(), MixAll.MASTER_ID, true); + if (findBrokerResult != null) { + LockBatchRequestBody requestBody = new LockBatchRequestBody(); + requestBody.setConsumerGroup(this.consumerGroup); + requestBody.setClientId(this.mQClientFactory.getClientId()); + requestBody.getMqSet().add(mq); + + try { + Set lockedMq = + this.mQClientFactory.getMQClientAPIImpl().lockBatchMQ(findBrokerResult.getBrokerAddr(), requestBody, 1000); + for (MessageQueue mmqq : lockedMq) { + ProcessQueue processQueue = this.processQueueTable.get(mmqq); + if (processQueue != null) { + processQueue.setLocked(true); + processQueue.setLastLockTimestamp(System.currentTimeMillis()); + } + } + + boolean lockOK = lockedMq.contains(mq); + log.info("the message queue lock {}, {} {}", + lockOK ? "OK" : "Failed", + this.consumerGroup, + mq); + return lockOK; + } catch (Exception e) { + log.warn("lockBatchMQ except, " + mq, e); + } + } + + return false; + } + + public void lockAll() { + HashMap> brokerMqs = this.buildProcessQueueTableByBrokerName(); + + Iterator>> it = brokerMqs.entrySet().iterator(); + while (it.hasNext()) { + Entry> entry = it.next(); + final String brokerName = entry.getKey(); + final Set mqs = entry.getValue(); + + if (mqs.isEmpty()) + continue; + + FindBrokerResult findBrokerResult = this.mQClientFactory.findBrokerAddressInSubscribe(brokerName, MixAll.MASTER_ID, true); + if (findBrokerResult != null) { + LockBatchRequestBody requestBody = new LockBatchRequestBody(); + requestBody.setConsumerGroup(this.consumerGroup); + requestBody.setClientId(this.mQClientFactory.getClientId()); + requestBody.setMqSet(mqs); + + try { + Set lockOKMQSet = + this.mQClientFactory.getMQClientAPIImpl().lockBatchMQ(findBrokerResult.getBrokerAddr(), requestBody, 1000); + + for (MessageQueue mq : lockOKMQSet) { + ProcessQueue processQueue = this.processQueueTable.get(mq); + if (processQueue != null) { + if (!processQueue.isLocked()) { + log.info("the message queue locked OK, Group: {} {}", this.consumerGroup, mq); + } + + processQueue.setLocked(true); + processQueue.setLastLockTimestamp(System.currentTimeMillis()); + } + } + for (MessageQueue mq : mqs) { + if (!lockOKMQSet.contains(mq)) { + ProcessQueue processQueue = this.processQueueTable.get(mq); + if (processQueue != null) { + processQueue.setLocked(false); + log.warn("the message queue locked Failed, Group: {} {}", this.consumerGroup, mq); + } + } + } + } catch (Exception e) { + log.warn("lockBatchMQ except, " + mqs, e); + } + } + } + } + + public void doRebalance(final boolean isOrder) { + long startTime = System.currentTimeMillis(); + Map subTable = this.getSubscriptionInner(); + if (subTable != null) { + Map subTableCopy = new HashMap(); + subTableCopy.putAll(subTable); + final CountDownLatch2 latch2 = new CountDownLatch2(subTableCopy.size()); + for (final Map.Entry entry : subTableCopy.entrySet()) { + final String topic = entry.getKey(); + + executorService.submit(new Runnable() { + @Override public void run() { + try { + rebalanceByTopic(topic, isOrder); + latch2.countDown(); + } catch (Throwable e) { + if (!topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) { + log.warn("rebalanceByTopic failed", e); + } + } + } + }); + } + try { + latch2.await(3, TimeUnit.SECONDS); + } catch (InterruptedException e) { + } + } + + long cost = System.currentTimeMillis() - startTime; + log.debug("doRebalance time {}", cost); + if (cost >= 1000) { + log.warn("doRebalance time {} too long", cost); + } + this.truncateMessageQueueNotMyTopic(); + } + + public ConcurrentMap getSubscriptionInner() { + return subscriptionInner; + } + + private void rebalanceByTopic(final String topic, final boolean isOrder) { + switch (messageModel) { + case BROADCASTING: { + Set mqSet = this.topicSubscribeInfoTable.get(topic); + + if (null == mqSet) { + this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic); + mqSet = this.topicSubscribeInfoTable.get(topic); + } + + if (mqSet != null) { + boolean changed = this.updateProcessQueueTableInRebalance(topic, mqSet, isOrder); + if (changed) { + this.messageQueueChanged(topic, mqSet, mqSet); + log.info("messageQueueChanged {} {} {} {}", + consumerGroup, + topic, + mqSet, + mqSet); + } + } else { + log.warn("doRebalance, {}, but the topic[{}] not exist.", consumerGroup, topic); + } + break; + } + case CLUSTERING: { + Set mqSet = this.topicSubscribeInfoTable.get(topic); + if (null == mqSet) { + this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic); + mqSet = this.topicSubscribeInfoTable.get(topic); + } + + List cidAll = this.mQClientFactory.findConsumerIdList(topic, consumerGroup); + + if (null == mqSet) { + if (!topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) { + log.warn("doRebalance, {}, but the topic[{}] not exist.", consumerGroup, topic); + } + } + + if (null == cidAll) { + log.warn("doRebalance, {} {}, get consumer id list failed", consumerGroup, topic); + } + + if (mqSet != null && cidAll != null) { + List mqAll = new ArrayList(); + mqAll.addAll(mqSet); + + Collections.sort(mqAll); + Collections.sort(cidAll); + + AllocateMessageQueueStrategy strategy = this.allocateMessageQueueStrategy; + + List allocateResult = null; + try { + allocateResult = strategy.allocate( + this.consumerGroup, + this.mQClientFactory.getClientId(), + mqAll, + cidAll); + } catch (Throwable e) { + log.warn("AllocateMessageQueueStrategy.allocate Exception. allocateMessageQueueStrategyName={}", strategy.getName(), + e); + return; + } + + Set allocateResultSet = new HashSet(); + if (allocateResult != null) { + allocateResultSet.addAll(allocateResult); + } + + boolean changed = this.updateProcessQueueTableInRebalance(topic, allocateResultSet, isOrder); + if (changed) { + log.info( + "rebalanced result changed. allocateMessageQueueStrategyName={}, group={}, topic={}, clientId={}, mqAllSize={}, cidAllSize={}, rebalanceResultSize={}, rebalanceResultSet={}", + strategy.getName(), consumerGroup, topic, this.mQClientFactory.getClientId(), mqSet.size(), cidAll.size(), + allocateResultSet.size(), allocateResultSet); + this.messageQueueChanged(topic, mqSet, allocateResultSet); + } + } + break; + } + default: + break; + } + } + + private void truncateMessageQueueNotMyTopic() { + Map subTable = this.getSubscriptionInner(); + + for (MessageQueue mq : this.processQueueTable.keySet()) { + if (!subTable.containsKey(mq.getTopic())) { + + ProcessQueue pq = this.processQueueTable.remove(mq); + if (pq != null) { + pq.setDropped(true); + log.info("doRebalance, {}, truncateMessageQueueNotMyTopic remove unnecessary mq, {}", consumerGroup, mq); + } + } + } + } + + private boolean updateProcessQueueTableInRebalance(final String topic, final Set mqSet, + final boolean isOrder) { + boolean changed = false; + + Iterator> it = this.processQueueTable.entrySet().iterator(); + while (it.hasNext()) { + Entry next = it.next(); + MessageQueue mq = next.getKey(); + ProcessQueue pq = next.getValue(); + + if (mq.getTopic().equals(topic)) { + if (!mqSet.contains(mq)) { + pq.setDropped(true); + if (this.removeUnnecessaryMessageQueue(mq, pq)) { + it.remove(); + changed = true; + log.info("doRebalance, {}, remove unnecessary mq, {}", consumerGroup, mq); + } + } else if (pq.isPullExpired()) { + switch (this.consumeType()) { + case CONSUME_ACTIVELY: + break; + case CONSUME_PASSIVELY: + pq.setDropped(true); + if (this.removeUnnecessaryMessageQueue(mq, pq)) { + it.remove(); + changed = true; + log.warn("[BUG]doRebalance, {}, remove unnecessary mq, {}, because pull is pause, so try to fixed it", + consumerGroup, mq); + } + break; + default: + break; + } + } + } + } + + List pullRequestList = new ArrayList(); + for (MessageQueue mq : mqSet) { + if (!this.processQueueTable.containsKey(mq)) { + if (isOrder && !this.lock(mq)) { + log.warn("doRebalance, {}, add a new mq failed, {}, because lock failed", consumerGroup, mq); + continue; + } + + this.removeDirtyOffset(mq); + ProcessQueue pq = new ProcessQueue(); + long nextOffset = this.computePullFromWhere(mq); + if (nextOffset >= 0) { + ProcessQueue pre = this.processQueueTable.putIfAbsent(mq, pq); + if (pre != null) { + log.info("doRebalance, {}, mq already exists, {}", consumerGroup, mq); + } else { + log.info("doRebalance, {}, add a new mq, {}", consumerGroup, mq); + PullRequest pullRequest = new PullRequest(); + pullRequest.setConsumerGroup(consumerGroup); + pullRequest.setNextOffset(nextOffset); + pullRequest.setMessageQueue(mq); + pullRequest.setProcessQueue(pq); + pullRequestList.add(pullRequest); + changed = true; + } + } else { + log.warn("doRebalance, {}, add new mq failed, {}", consumerGroup, mq); + } + } + } + + this.dispatchPullRequest(pullRequestList); + + return changed; + } + + public abstract void messageQueueChanged(final String topic, final Set mqAll, + final Set mqDivided); + + public abstract boolean removeUnnecessaryMessageQueue(final MessageQueue mq, final ProcessQueue pq); + + public abstract ConsumeType consumeType(); + + public abstract void removeDirtyOffset(final MessageQueue mq); + + public abstract long computePullFromWhere(final MessageQueue mq); + + public abstract void dispatchPullRequest(final List pullRequestList); + + public void removeProcessQueue(final MessageQueue mq) { + ProcessQueue prev = this.processQueueTable.remove(mq); + if (prev != null) { + boolean droped = prev.isDropped(); + prev.setDropped(true); + this.removeUnnecessaryMessageQueue(mq, prev); + log.info("Fix Offset, {}, remove unnecessary mq, {} Droped: {}", consumerGroup, mq, droped); + } + } + + public ConcurrentMap getProcessQueueTable() { + return processQueueTable; + } + + public ConcurrentMap> getTopicSubscribeInfoTable() { + return topicSubscribeInfoTable; + } + + public String getConsumerGroup() { + return consumerGroup; + } + + public void setConsumerGroup(String consumerGroup) { + this.consumerGroup = consumerGroup; + } + + public MessageModel getMessageModel() { + return messageModel; + } + + public void setMessageModel(MessageModel messageModel) { + this.messageModel = messageModel; + } + + public AllocateMessageQueueStrategy getAllocateMessageQueueStrategy() { + return allocateMessageQueueStrategy; + } + + public void setAllocateMessageQueueStrategy(AllocateMessageQueueStrategy allocateMessageQueueStrategy) { + this.allocateMessageQueueStrategy = allocateMessageQueueStrategy; + } + + public MQClientInstance getmQClientFactory() { + return mQClientFactory; + } + + public void setmQClientFactory(MQClientInstance mQClientFactory) { + this.mQClientFactory = mQClientFactory; + } + + public void destroy() { + Iterator> it = this.processQueueTable.entrySet().iterator(); + while (it.hasNext()) { + Entry next = it.next(); + next.getValue().setDropped(true); + } + + this.processQueueTable.clear(); + } + + public void shutdownRebalanceThreadPool(){ + this.executorService.shutdown(); + while (!executorService.isTerminated()) { + try { + executorService.awaitTermination(10, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + log.warn("", e); + } + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java new file mode 100644 index 0000000000..7e0303586b --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.client.impl.consumer; + +import cn.webank.emesher.threads.ThreadPoolHelper; +import org.apache.rocketmq.client.impl.factory.MQClientInstance; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.common.ServiceThread; +import org.apache.rocketmq.logging.InternalLogger; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Rebalance Service + */ +public class RebalanceService extends ServiceThread { + private static long waitInterval = + Long.parseLong(System.getProperty( + "rocketmq.client.rebalance.waitInterval", "10000")); + private final InternalLogger log = ClientLogger.getLog(); + private final MQClientInstance mqClientFactory; + private final ReentrantLock lock = new ReentrantLock(); + private ScheduledExecutorService scheduler = ThreadPoolHelper.getRebalanceServiceExecutorService(); + + private AtomicBoolean isNotified = new AtomicBoolean(false); + + public RebalanceService(MQClientInstance mqClientFactory) { + super(true); + this.mqClientFactory = mqClientFactory; + } + + public void wakeup() { + if (!isStopped() && isNotified.compareAndSet(false, true) && !lock.isLocked()) { + scheduler.execute(new Runnable() { + private static final String tag = "RebalanceServiceTask"; + + public void run() { + if (!lock.tryLock()) return; + try { + while (!RebalanceService.this.isStopped() && RebalanceService.this.isNotified.get()) work(); + } finally { + lock.unlock(); + } + } + }); + } + } + + public void start() { + scheduler.scheduleWithFixedDelay(new Runnable() { + private static final String tag = "ScheduledRebalanceServiceTask"; + + public void run() { + try { + lock.lock(); + if (!RebalanceService.this.isStopped()) work(); + while (!RebalanceService.this.isStopped() && RebalanceService.this.isNotified.get()) work(); + } finally { + if (lock.isHeldByCurrentThread()) + lock.unlock(); + } + } + }, waitInterval, waitInterval, TimeUnit.MILLISECONDS); + } + + private void work() { + RebalanceService.this.isNotified.set(false); + RebalanceService.this.mqClientFactory.doRebalance(); + } + + @Override + public void run() { + if (4 > 3) throw new UnsupportedOperationException("proxy internal bug."); +// log.info(this.getServiceName() + " service started"); +// +// while (!this.isStopped()) { +// this.waitForRunning(waitInterval); +// this.mqClientFactory.doRebalance(); +// } +// +// log.info(this.getServiceName() + " service end"); + } + + + @Override + public String getServiceName() { + return RebalanceService.class.getSimpleName(); + } + + public void makeStop() { + this.stopped = true; + scheduler.shutdown(); + } + + public void shutdown() { + makeStop(); + } + + public void shutdown(final boolean interrupt) { + makeStop(); + } + + public void stop(final boolean interrupt) { + makeStop(); + } + + public void stop() { + makeStop(); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/controller/ClientManageControllerTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/controller/ClientManageControllerTest.java new file mode 100644 index 0000000000..715a5ada29 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/controller/ClientManageControllerTest.java @@ -0,0 +1,57 @@ +/* + * 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.runtime.admin.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.admin.rocketmq.controller.AdminController; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; + +import java.io.IOException; + +import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import com.sun.net.httpserver.HttpServer; + +public class ClientManageControllerTest { + + @Test + public void testStart() throws IOException { + EventMeshTCPServer eventMeshTCPServer = mock(EventMeshTCPServer.class); + AdminController adminController = mock(AdminController.class); + EventMeshTCPConfiguration tcpConfiguration = mock(EventMeshTCPConfiguration.class); + doNothing().when(tcpConfiguration).init(); + when(eventMeshTCPServer.getEventMeshTCPConfiguration()).thenReturn(tcpConfiguration); + ClientManageController controller = new ClientManageController(eventMeshTCPServer); + try (MockedStatic dummyStatic = Mockito.mockStatic(HttpServer.class)) { + HttpServer server = mock(HttpServer.class); + dummyStatic.when(() -> HttpServer.create(any(), anyInt())).thenReturn(server); + Mockito.doNothing().when(adminController).run(server); + controller.start(); + } + } +} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/QueryRecommendEventMeshHandlerTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/QueryRecommendEventMeshHandlerTest.java new file mode 100644 index 0000000000..1112cedab7 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/QueryRecommendEventMeshHandlerTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.eventmesh.runtime.admin.handler; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendImpl; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.net.URI; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.MockedConstruction; + +import com.sun.net.httpserver.HttpExchange; + +public class QueryRecommendEventMeshHandlerTest { + + @Test + public void testHandle() throws Exception { + HttpExchange httpExchange = mock(HttpExchange.class); + URI uri = mock(URI.class); + when(uri.getQuery()).thenReturn("group=group&purpose=purpose"); + when(httpExchange.getRequestURI()).thenReturn(uri); + + // mock eventMeshTCPServer + EventMeshTCPServer eventMeshTCPServer = mock(EventMeshTCPServer.class); + EventMeshTCPConfiguration tcpConfiguration = mock(EventMeshTCPConfiguration.class); + doNothing().when(tcpConfiguration).init(); + tcpConfiguration.eventMeshServerRegistryEnable = true; + when(eventMeshTCPServer.getEventMeshTCPConfiguration()).thenReturn(tcpConfiguration); + + OutputStream outputStream = new ByteArrayOutputStream(); + when(httpExchange.getResponseBody()).thenReturn(outputStream); + + QueryRecommendEventMeshHandler handler = new QueryRecommendEventMeshHandler(eventMeshTCPServer); + try (MockedConstruction ignored = mockConstruction(EventMeshRecommendImpl.class, + (mock, context) -> when(mock.calculateRecommendEventMesh(anyString(), anyString())).thenReturn("result"))) { + handler.handle(httpExchange); + String response = outputStream.toString(); + Assert.assertEquals("result", response); + } + } +} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByPathHandlerTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByPathHandlerTest.java new file mode 100644 index 0000000000..e6af25c3cd --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByPathHandlerTest.java @@ -0,0 +1,108 @@ +/* + * 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.runtime.admin.handler; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.util.NetUtils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import com.sun.net.httpserver.HttpExchange; + +public class RedirectClientByPathHandlerTest { + + @Mock + private EventMeshTCPServer eventMeshTCPServer; + + @Before + public void init() { + MockitoAnnotations.openMocks(this); + } + + @Test + public void testHandle() throws IOException { + OutputStream outputStream = new ByteArrayOutputStream(); + + ClientSessionGroupMapping mapping = mock(ClientSessionGroupMapping.class); + when(eventMeshTCPServer.getClientSessionGroupMapping()).thenReturn(mapping); + + // mock session map + ConcurrentHashMap sessionMap = new ConcurrentHashMap<>(); + Session session = mock(Session.class); + UserAgent agent = mock(UserAgent.class); + when(agent.getPath()).thenReturn("path"); + when(session.getClient()).thenReturn(agent); + sessionMap.put(new InetSocketAddress(8080), session); + when(mapping.getSessionMap()).thenReturn(sessionMap); + + RedirectClientByPathHandler redirectClientByPathHandler = new RedirectClientByPathHandler(eventMeshTCPServer); + + HttpExchange mockExchange = mock(HttpExchange.class); + when(mockExchange.getResponseBody()).thenReturn(outputStream); + + // mock uri + URI uri = mock(URI.class); + when(uri.getQuery()).thenReturn("path=path&ip=127.0.0.1&port=1234&desteventMeshIp=127.0.0.1&desteventmeshport=8080"); + when(mockExchange.getRequestURI()).thenReturn(uri); + + try (MockedStatic netUtilsMockedStatic = Mockito.mockStatic(NetUtils.class)) { + Map queryStringInfo = new HashMap<>(); + queryStringInfo.put(EventMeshConstants.MANAGE_PATH, EventMeshConstants.MANAGE_PATH); + queryStringInfo.put(EventMeshConstants.MANAGE_DEST_IP, "127.0.0.1"); + queryStringInfo.put(EventMeshConstants.MANAGE_DEST_PORT, "8080"); + netUtilsMockedStatic.when(() -> NetUtils.formData2Dic(anyString())).thenReturn(queryStringInfo); + + try (MockedStatic clientMockedStatic = Mockito.mockStatic(EventMeshTcp2Client.class)) { + clientMockedStatic.when(() -> EventMeshTcp2Client.redirectClient2NewEventMesh(any(), anyString(), anyInt(), any(), + any())).thenReturn("redirectResult"); + redirectClientByPathHandler.handle(mockExchange); + + String response = outputStream.toString(); + Assert.assertTrue(response.contains("redirectClientByPath success")); + } + } + } +} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/ProxyClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/ProxyClient.java new file mode 100644 index 0000000000..861e8987ee --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/ProxyClient.java @@ -0,0 +1,55 @@ +/* + * 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 client; + +import client.hook.ReceiveMsgHook; +import cn.webank.eventmesh.common.protocol.tcp.Package; +public interface ProxyClient { + + Package rr(Package msg, long timeout) throws Exception; + + Package publish(Package msg, long timeout) throws Exception; + + Package broadcast(Package msg, long timeout) throws Exception; + + void init() throws Exception; + + void close(); + + void heartbeat() throws Exception; + + Package listen() throws Exception; + + Package justSubscribe(String serviceId, String scenario, String dcn) throws Exception; + + Package justUnsubscribe(String serviceId, String scenario, String dcn) throws Exception; + + Package justSubscribe(String topic) throws Exception; + + Package justUnsubscribe(String topic) throws Exception; + + void registerPubBusiHandler(ReceiveMsgHook handler) throws Exception; + + void registerSubBusiHandler(ReceiveMsgHook handler) throws Exception; + +// void sysLog() throws Exception; +// +// void traceLog() throws Exception; + + void goodbye() throws Exception; +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/hook/ReceiveMsgHook.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/hook/ReceiveMsgHook.java index a81dc7e566..042e98cef8 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/hook/ReceiveMsgHook.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/hook/ReceiveMsgHook.java @@ -15,9 +15,13 @@ * limitations under the License. */ +<<<<<<<< HEAD:eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/hook/ReceiveMsgHook.java package org.apache.eventmesh.runtime.client.hook; import org.apache.eventmesh.common.protocol.tcp.Package; +======== +package org.apache.eventmesh.client.tcp.common; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/ReceiveMsgHook.java import io.netty.channel.ChannelHandlerContext; diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/ProxyClientImpl.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/ProxyClientImpl.java new file mode 100644 index 0000000000..0a2f4e107f --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/ProxyClientImpl.java @@ -0,0 +1,173 @@ +/* + * 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.runtime.client.impl; + +<<<<<<<< HEAD:eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/ProxyClientImpl.java +import client.ProxyClient; +import client.PubClient; +import client.SubClient; +import client.common.UserAgentUtils; +import client.hook.ReceiveMsgHook; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +======== +import org.apache.eventmesh.common.protocol.SubcriptionType; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.tcp.UserAgent; + +import org.apache.eventmesh.runtime.client.api.EventMeshClient; +import org.apache.eventmesh.runtime.client.api.PubClient; +import org.apache.eventmesh.runtime.client.api.SubClient; +import org.apache.eventmesh.runtime.client.common.UserAgentUtils; +import org.apache.eventmesh.runtime.client.hook.ReceiveMsgHook; +>>>>>>>> c12ebebc1 ([ISSUE #442] Fix findings filtered by Checkstyle workflow (#443)):eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/EventMeshClientImpl.java + +public class ProxyClientImpl implements ProxyClient { + protected UserAgent agent; + private String accessHost; + private int accessPort; + + private PubClient pubClient; + private SubClient subClient; + + public ProxyClientImpl(String accessHost, int accessPort, UserAgent agent) { + this.accessHost = accessHost; + this.accessPort = accessPort; + this.agent = agent; + this.subClient = new SubClientImpl(accessHost, accessPort, agent); + this.pubClient = new PubClientImpl(accessHost, accessPort, agent); + } + + public ProxyClientImpl(String accessHost, int accessPort) { + this.accessHost = accessHost; + this.accessPort = accessPort; + this.subClient = new SubClientImpl(accessHost, accessPort, UserAgentUtils.createSubUserAgent()); + this.pubClient = new PubClientImpl(accessHost, accessPort, UserAgentUtils.createPubUserAgent()); + } + + public Package rr(Package msg, long timeout) throws Exception { + return this.pubClient.rr(msg, timeout); + } + + public Package publish(Package msg, long timeout) throws Exception { + return this.pubClient.publish(msg, timeout); + } + + public Package broadcast(Package msg, long timeout) throws Exception { + return this.pubClient.broadcast(msg, timeout); + } + + public void init() throws Exception { + this.subClient.init(); + this.pubClient.init(); + } + + public void close() { + this.pubClient.close(); + this.subClient.close(); + } + + public void heartbeat() throws Exception { + this.pubClient.heartbeat(); + this.subClient.heartbeat(); + } + +<<<<<<<< HEAD:eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/ProxyClientImpl.java + public Package justSubscribe(String serviceId, String scenario, String dcn) throws Exception { + return this.subClient.justSubscribe(serviceId, scenario, dcn); + } + +======== +>>>>>>>> c12ebebc1 ([ISSUE #442] Fix findings filtered by Checkstyle workflow (#443)):eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/EventMeshClientImpl.java + public Package listen() throws Exception { + return this.subClient.listen(); + } + +<<<<<<<< HEAD:eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/ProxyClientImpl.java + public Package justUnsubscribe(String serviceId, String scenario, String dcn) throws Exception { + return this.subClient.justUnsubscribe(serviceId, scenario, dcn); + } + + @Override + public Package justSubscribe(String topic) throws Exception { + return this.subClient.justSubscribe(topic); + } + + @Override + public Package justUnsubscribe(String topic) throws Exception { + return this.subClient.justUnsubscribe(topic); +======== + @Override + public Package justSubscribe(String topic, SubscriptionMode subscriptionMode, + SubcriptionType subcriptionType) throws Exception { + return this.subClient.justSubscribe(topic, subscriptionMode, subcriptionType); + } + + @Override + public Package justUnsubscribe(String topic, SubscriptionMode subscriptionMode, + SubcriptionType subcriptionType) throws Exception { + return this.subClient.justUnsubscribe(topic, subscriptionMode, subcriptionType); +>>>>>>>> c12ebebc1 ([ISSUE #442] Fix findings filtered by Checkstyle workflow (#443)):eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/EventMeshClientImpl.java + } + + public void registerSubBusiHandler(ReceiveMsgHook handler) throws Exception { + this.subClient.registerBusiHandler(handler); + } + + public void registerPubBusiHandler(ReceiveMsgHook handler) throws Exception { + this.pubClient.registerBusiHandler(handler); + } + + @Override + public String toString() { + return "AccessClientImpl{" + + "accessHost='" + accessHost + '\'' + + ", accessPort=" + accessPort + + ", agent=" + agent + + '}'; + } + + @Deprecated + public ProxyClientImpl(String accessServer, String busiTag, String subSystem) { +// this.accessServer = accessServer; +// this.pubClient = new PubClientImpl(StringUtils.split(this.accessServer, ":")[0], +// Integer.parseInt(StringUtils.split(this.accessServer, ":")[1]), OldTestUserAgentFactory.createPubUserAgent +// (busiTag, subSystem)); +// this.subClient = new SubClientImpl(StringUtils.split(this.accessServer, ":")[0], +// Integer.parseInt(StringUtils.split(this.accessServer, ":")[1]), OldTestUserAgentFactory.createSubUserAgent +// (busiTag, subSystem)); + } + +// @Override +// public void sysLog() throws Exception { +// subClient.sysLog(); +// } +// +// @Override +// public void traceLog() throws Exception { +// subClient.traceLog(); +// } + + @Override + public void goodbye() throws Exception { + subClient.goodbye(); + pubClient.goodbye(); + } + +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshThreadFactoryImplTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshThreadFactoryImplTest.java new file mode 100644 index 0000000000..f9b4821852 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshThreadFactoryImplTest.java @@ -0,0 +1,39 @@ +/* + * 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.runtime.util; + +import org.junit.Assert; +import org.junit.Test; + +public class EventMeshThreadFactoryImplTest { + + @Test + public void testGetThreadNamePrefix() { + final String threadNamePrefix = "threadNamePrefix"; + EventMeshThreadFactoryImpl factory = new EventMeshThreadFactoryImpl(threadNamePrefix, false); + Assert.assertEquals(threadNamePrefix, factory.getThreadNamePrefix()); + } + + @Test + public void testNewThread() { + final String threadNamePrefix = "threadNamePrefix"; + EventMeshThreadFactoryImpl factory = new EventMeshThreadFactoryImpl(threadNamePrefix, true); + Thread t = factory.newThread(() -> {}); + Assert.assertNotNull(t); + } +} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/IOTinyUtilsTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/IOTinyUtilsTest.java new file mode 100644 index 0000000000..5e1fd977b1 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/IOTinyUtilsTest.java @@ -0,0 +1,88 @@ +/* + * 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.runtime.util; + + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.when; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.MockedConstruction; + +public class IOTinyUtilsTest { + + @Test + public void testCopy() throws Exception { + BufferedReader input = mock(BufferedReader.class); + BufferedWriter output = mock(BufferedWriter.class); + int count = 10; + char[] buffer = new char[1 << 12]; + doNothing().when(output).write(buffer, 0, count); + when(input.read(buffer)).thenReturn(10, 10 , -1); + long result = IOTinyUtils.copy(input, output); + Assert.assertEquals(result, count*2); + } + + @Test + public void testReadLines() throws IOException { + BufferedReader input = mock(BufferedReader.class); + when(input.readLine()).thenReturn("hello", "world", null); + List result = IOTinyUtils.readLines(input); + Assert.assertEquals(result.get(0), "hello"); + } + + @Test + public void testCopyFile() { + } + + @Test + public void testCleanDirectory() throws IOException { + File dirFile = mock(File.class); + when(dirFile.exists()).thenReturn(true); + when(dirFile.isDirectory()).thenReturn(true); + + File normalFile = mock(File.class); + when(normalFile.exists()).thenReturn(true); + when(normalFile.isDirectory()).thenReturn(false); + when(normalFile.delete()).thenReturn(true); + + File[] files = {normalFile}; + when(dirFile.listFiles()).thenReturn(files); + IOTinyUtils.cleanDirectory(dirFile); + } + + @Test + public void testWriteStringToFile() throws IOException { + File file = mock(File.class); + try (MockedConstruction ignored = mockConstruction(FileOutputStream.class, + (mock, context) -> doNothing().when(mock).write(any()))) { + IOTinyUtils.writeStringToFile(file, "data", "utf-8"); + } + } +} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/NetUtilsTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/NetUtilsTest.java new file mode 100644 index 0000000000..d2786ffef3 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/NetUtilsTest.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.runtime.util; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +public class NetUtilsTest { + + @Test + public void testFormData2Dic() { + String formData = ""; + Map result = NetUtils.formData2Dic(formData); + Assert.assertTrue(result.isEmpty()); + + formData = "item_id=10081&item_name=test item name"; + result = NetUtils.formData2Dic(formData); + Assert.assertEquals(result.get("item_id"), "10081"); + } + + @Test + public void testAddressToString() { + List clients = new ArrayList<>(); + String result = NetUtils.addressToString(clients); + Assert.assertEquals(result, "no session had been closed"); + + InetSocketAddress localAddress = new InetSocketAddress(80); + clients.add(localAddress); + result = NetUtils.addressToString(clients); + Assert.assertEquals(result, localAddress.toString()); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/WebhookUtilTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/WebhookUtilTest.java new file mode 100644 index 0000000000..c19720f7bb --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/WebhookUtilTest.java @@ -0,0 +1,69 @@ +/* + @Test + * 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.runtime.util; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; + +import org.apache.eventmesh.api.auth.AuthService; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.message.BasicHeader; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +public class WebhookUtilTest { + + @Test + public void testObtainDeliveryAgreement() throws Exception { + CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); + CloseableHttpResponse response = Mockito.mock(CloseableHttpResponse.class); + Mockito.when(response.getLastHeader("WebHook-Allowed-Origin")).thenReturn(new BasicHeader("WebHook-Allowed-Origin", "*")); + Mockito.when(httpClient.execute(any())).thenReturn(response); + Assert.assertTrue(WebhookUtil.obtainDeliveryAgreement(httpClient, "https://eventmesh.apache.org", "*")); + } + + @Test + public void testSetWebhookHeaders() { + String authType = "auth-http-basic"; + AuthService authService = mock(AuthService.class); + doNothing().when(authService).init(); + Map authParams = new HashMap<>(); + String key = "Authorization", value = "Basic ****"; + authParams.put(key, value); + Mockito.when(authService.getAuthParams()).thenReturn(authParams); + + try (MockedStatic dummyStatic = Mockito.mockStatic(EventMeshExtensionFactory.class)) { + dummyStatic.when(() -> EventMeshExtensionFactory.getExtension(AuthService.class, authType)).thenReturn(authService); + HttpPost post = new HttpPost(); + WebhookUtil.setWebhookHeaders(post, "application/json", "eventmesh.FT", authType); + Assert.assertEquals(post.getLastHeader(key).getValue(), value); + } + } +} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/protocol/CmdAsync2ClientTest.java b/eventmesh-runtime/src/test/java/protocol/CmdAsync2ClientTest.java new file mode 100644 index 0000000000..758d2a1a48 --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdAsync2ClientTest.java @@ -0,0 +1,68 @@ +/* + * 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 protocol; + +import client.PubClient; +import client.common.Server; +import client.common.UserAgentUtils; +import client.hook.ReceiveMsgHook; +import client.impl.PubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import io.netty.channel.ChannelHandlerContext; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Cmd Test: Async Message To Client + */ +public class CmdAsync2ClientTest { + + public static Server server = new Server(); + public static PubClient client = new PubClientImpl("127.0.0.1", 10000, UserAgentUtils.createSubUserAgent()); + + @BeforeClass + public static void before_Cmd_AsyncMessage() throws Exception { + server.startAccessServer(); + client.init(); + } + + @Test + public void test_Cmd_AsyncMessage() throws Exception { + client.registerBusiHandler(new ReceiveMsgHook() { + @Override + public void handle(Package msg, ChannelHandlerContext ctx) { + System.err.println("receive response from server:------------------" + msg.toString()); + if (msg.getHeader().getCommand() == Command.CLIENT_GOODBYE_RESPONSE) { + Assert.assertTrue("HEARTBEAT_RESPONSE", true); + } + } + }); + Package msg = new Package(); + client.publish(msg, 3000); +// Thread.sleep(10000); + } + + @AfterClass + public static void after_Cmd_AsyncMessage() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdAsync2ServerTest.java b/eventmesh-runtime/src/test/java/protocol/CmdAsync2ServerTest.java new file mode 100644 index 0000000000..07983dfb69 --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdAsync2ServerTest.java @@ -0,0 +1,59 @@ +/* + * 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 protocol; + +import client.PubClient; +import client.common.MessageUtils; +import client.common.Server; +import client.common.UserAgentUtils; +import client.impl.PubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CmdAsync2ServerTest { + + public static Server server = new Server(); + public static PubClient client = new PubClientImpl("127.0.0.1", 10000, UserAgentUtils.createSubUserAgent()); + + @BeforeClass + public static void before_Cmd_AsyncMessage2Server() throws Exception { + server.startAccessServer(); + client.init(); + Thread.sleep(1000); + } + + @Test + public void test_Cmd_AsyncMessage2Server() throws Exception { + Package msg = MessageUtils.asyncMessage("FT0-e-80010000-01-1", 0); + Package replyMsg = client.publish(msg, 3000); + System.err.println("Reply Message-----------------------------------------" + replyMsg.toString()); + if (replyMsg.getHeader().getCommand() != Command.ASYNC_MESSAGE_TO_SERVER_ACK) { + Assert.assertTrue("ASYNC_MESSAGE_TO_SERVER_ACK FAIL", false); + } + } + + @AfterClass + public static void after_Cmd_AsyncMessage2Server() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdBroadCast2ClientTest.java b/eventmesh-runtime/src/test/java/protocol/CmdBroadCast2ClientTest.java new file mode 100644 index 0000000000..a750815865 --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdBroadCast2ClientTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package protocol; + +import client.SubClient; +import client.common.Server; +import client.common.UserAgentUtils; +import client.hook.ReceiveMsgHook; +import client.impl.SubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import io.netty.channel.ChannelHandlerContext; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Cmd Test: BroadCast To Client + */ +public class CmdBroadCast2ClientTest { + + public static Server server = new Server(); + public static SubClient client = new SubClientImpl("127.0.0.1", 10000, UserAgentUtils.createSubUserAgent()); + + @BeforeClass + public static void before_Cmd_broadcast() throws Exception { + server.startAccessServer(); + client.init(); + } + + @Test + public void test_Cmd_broadcast() throws Exception { + client.registerBusiHandler(new ReceiveMsgHook() { + @Override + public void handle(Package msg, ChannelHandlerContext ctx) { + System.err.println("receive response from server:------------------" + msg.toString()); + if (msg.getHeader().getCommand() == Command.BROADCAST_MESSAGE_TO_CLIENT) { + Assert.assertTrue("HEARTBEAT_RESPONSE", true); + } + } + }); + Package msg = new Package(); +// client.publish(msg,3000); +// Thread.sleep(10000); + } + + @AfterClass + public static void after_Cmd_broadcast() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } + +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdBroadCast2ServerTest.java b/eventmesh-runtime/src/test/java/protocol/CmdBroadCast2ServerTest.java new file mode 100644 index 0000000000..2067042bd5 --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdBroadCast2ServerTest.java @@ -0,0 +1,60 @@ +/* + * 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 protocol; + +import client.PubClient; +import client.common.MessageUtils; +import client.common.Server; +import client.common.UserAgentUtils; +import client.impl.PubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CmdBroadCast2ServerTest { + + public static Server server = new Server(); + public static PubClient client = new PubClientImpl("127.0.0.1", 10000, UserAgentUtils.createSubUserAgent()); + + @BeforeClass + public static void before_Cmd_broadcast2Server() throws Exception { + server.startAccessServer(); + client.init(); + Thread.sleep(1000); + } + + @Test + public void test_Cmd_broadcast2Server() throws Exception { + Package msg = MessageUtils.broadcastMessage("FT0-e-80030000-01-3", 0); + Package replyMsg = client.broadcast(msg, 3000); + System.err.println("Reply Message-----------------------------------------" + replyMsg.toString()); + if (replyMsg.getHeader().getCommand() != Command.BROADCAST_MESSAGE_TO_SERVER_ACK) { + Assert.assertTrue("BROADCAST_MESSAGE_TO_SERVER_ACK FAIL", false); + } + } + + @AfterClass + public static void after_Cmd_broadcast2Server() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } + +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdClientGoodByTest.java b/eventmesh-runtime/src/test/java/protocol/CmdClientGoodByTest.java new file mode 100644 index 0000000000..5d767bec41 --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdClientGoodByTest.java @@ -0,0 +1,59 @@ +/* + * 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 protocol; + +import client.SubClient; +import client.common.Server; +import client.common.UserAgentUtils; +import client.impl.SubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test Cmd: CLIENT_GOODBYE_REQUEST + */ +public class CmdClientGoodByTest { + public static Server server = new Server(); + public static SubClient client = new SubClientImpl("127.0.0.1", 10000, UserAgentUtils.createSubUserAgent()); + + @BeforeClass + public static void before_Cmd_client_goodbye() throws Exception { + server.startAccessServer(); + client.init(); + Thread.sleep(1000); + } + + @Test + public void test_Cmd_client_goodbye() throws Exception { + Package replyMsg = client.goodbye(); + System.err.println("Reply Message-----------------------------------------" + replyMsg.toString()); + if (replyMsg.getHeader().getCommand() != Command.CLIENT_GOODBYE_RESPONSE) { + Assert.assertTrue("CLIENT_GOODBYE_RESPONSE FAIL", false); + } + } + + @AfterClass + public static void after_Cmd_client_goodbye() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdHeartbeatTest.java b/eventmesh-runtime/src/test/java/protocol/CmdHeartbeatTest.java new file mode 100644 index 0000000000..a30d98588b --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdHeartbeatTest.java @@ -0,0 +1,68 @@ +/* + * 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 protocol; + +import client.PubClient; +import client.common.Server; +import client.common.UserAgentUtils; +import client.hook.ReceiveMsgHook; +import client.impl.PubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import io.netty.channel.ChannelHandlerContext; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Cmd Test : HeartBeat + */ +public class CmdHeartbeatTest { + public static Server server = new Server(); + public static PubClient client = new PubClientImpl("127.0.0.1", 10000, UserAgentUtils.createPubUserAgent()); + + @BeforeClass + public static void before_Cmd_hearbeat() throws Exception { + server.startAccessServer(); + client.init(); + Thread.sleep(1000); + } + + @Test + public void test_Cmd_heartbeat() throws Exception { + client.registerBusiHandler(new ReceiveMsgHook() { + @Override + public void handle(Package msg, ChannelHandlerContext ctx) { + System.err.println("receive response from server:------------------" + msg.toString()); + if (msg.getHeader().getCommand() != Command.HEARTBEAT_RESPONSE) { + Assert.assertTrue("HEARTBEAT_RESPONSE", false); + } + } + }); + client.heartbeat(); + + Thread.sleep(10000); + } + + @AfterClass + public static void after_Cmd_heartbeat() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdHelloTest.java b/eventmesh-runtime/src/test/java/protocol/CmdHelloTest.java new file mode 100644 index 0000000000..c472c384bc --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdHelloTest.java @@ -0,0 +1,36 @@ +/* + * 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 protocol; + +import client.common.Server; +import org.junit.Test; + +public class CmdHelloTest { + + @Test + public void test_Cmd_Hello() throws Exception { + Server server = new Server(); + server.startAccessServer(); + + //do protocol send/receive + + Thread.sleep(3000); + server.shutdownAccessServer(); + } + +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdListenTest.java b/eventmesh-runtime/src/test/java/protocol/CmdListenTest.java new file mode 100644 index 0000000000..4a66480012 --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdListenTest.java @@ -0,0 +1,59 @@ +/* + * 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 protocol; + +import client.SubClient; +import client.common.Server; +import client.common.UserAgentUtils; +import client.impl.SubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Cmd Test: LISTEN_REQUEST + */ +public class CmdListenTest { + public static Server server = new Server(); + public static SubClient client = new SubClientImpl("127.0.0.1", 10000, UserAgentUtils.createSubUserAgent()); + + @BeforeClass + public static void before_Cmd_listen() throws Exception { + server.startAccessServer(); + client.init(); + Thread.sleep(1000); + } + + @AfterClass + public static void after_Cmd_listen() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } + + @Test + public void test_Cmd_listen() throws Exception { + Package replyMsg = client.listen(); + System.err.println("Reply Message-----------------------------------------" + replyMsg.toString()); + if (replyMsg.getHeader().getCommand() != Command.LISTEN_RESPONSE) { + Assert.assertTrue("SUBSCRIBE_RESPONSE FAIL", false); + } + } +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdRecommendTest.java b/eventmesh-runtime/src/test/java/protocol/CmdRecommendTest.java new file mode 100644 index 0000000000..087b0271d7 --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdRecommendTest.java @@ -0,0 +1,59 @@ +/* + * 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 protocol; + +import client.PubClient; +import client.common.Server; +import client.common.UserAgentUtils; +import client.impl.PubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CmdRecommendTest { + public static Server server = new Server(); + public static PubClient client = new PubClientImpl("127.0.0.1", 10000, UserAgentUtils.createPubUserAgent()); + + @BeforeClass + public static void before_Cmd_Recommend() throws Exception { + server.startAccessServer(); + client.init(); + Thread.sleep(1000); + } + + @AfterClass + public static void after_Cmd_Recommend() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } + + @Test + public void test_Cmd_Recommend() throws Exception { + + Package replyMsg = client.askRecommend(); + System.err.println("Reply Message-----------------------------------------" + replyMsg.toString()); + if (replyMsg.getHeader().getCommand() != Command.RECOMMEND_RESPONSE) { + Assert.assertTrue("RECOMMEND_RESPONSE FAIL", false); + } + } + + +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdSendRRTest.java b/eventmesh-runtime/src/test/java/protocol/CmdSendRRTest.java new file mode 100644 index 0000000000..1813565fc9 --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdSendRRTest.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 protocol; + +import client.PubClient; +import client.SubClient; +import client.common.MessageUtils; +import client.common.Server; +import client.common.UserAgentUtils; +import client.impl.PubClientImpl; +import client.impl.SubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CmdSendRRTest { + + public static Server server = new Server(); + public static PubClient client = new PubClientImpl("127.0.0.1", 10000, UserAgentUtils.createPubUserAgent()); + public static SubClient subClient = new SubClientImpl("127.0.0.1", 10000, UserAgentUtils.createUserAgent()); + + @BeforeClass + public static void before_Cmd_RR() throws Exception { + server.startAccessServer(); + client.init(); + Thread.sleep(1000); + } + + @Test + public void test_Cmd_RR() throws Exception { + Package msg = MessageUtils.rrMesssage("FT0-s-80000000-01-0", 0); + Package replyMsg = client.rr(msg, 5000); + System.err.println("收到回复:" + replyMsg.toString()); + if (replyMsg.getHeader().getCommand() != Command.RESPONSE_TO_CLIENT) { + Assert.assertTrue("RESPONSE_TO_CLIENT FAIL", false); + } + Thread.sleep(1000); + } + + @AfterClass + public static void after_Cmd_RR() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdSubscribeTest.java b/eventmesh-runtime/src/test/java/protocol/CmdSubscribeTest.java new file mode 100644 index 0000000000..b14d4bd4f6 --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdSubscribeTest.java @@ -0,0 +1,59 @@ +/* + * 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 protocol; + +import client.SubClient; +import client.common.Server; +import client.common.UserAgentUtils; +import client.impl.SubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +/** + * Test Cmd: SUBSCRIBE_REQUEST + */ +public class CmdSubscribeTest { + + public static Server server = new Server(); + public static SubClient client = new SubClientImpl("127.0.0.1", 10000, UserAgentUtils.createSubUserAgent()); + + @BeforeClass + public static void before_Cmd_subscribe() throws Exception { + server.startAccessServer(); + client.init(); + Thread.sleep(1000); + } + + @AfterClass + public static void after_Cmd_subscribe() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } + + @Test + public void test_Cmd_subscribe() throws Exception { + Package replyMsg = client.justSubscribe("FT0-s-80000000-01-0"); + System.err.println("Reply Message------------------" + replyMsg.toString()); + if (replyMsg.getHeader().getCommand() != Command.SUBSCRIBE_RESPONSE) { + Assert.assertTrue("SUBSCRIBE_RESPONSE FAIL", false); + } + } +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdSysLogTest.java b/eventmesh-runtime/src/test/java/protocol/CmdSysLogTest.java new file mode 100644 index 0000000000..5256b2770d --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdSysLogTest.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 protocol; + +import client.SubClient; +import client.common.Server; +import client.common.UserAgentUtils; +import client.hook.ReceiveMsgHook; +import client.impl.SubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import io.netty.channel.ChannelHandlerContext; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test Cmd: SYS_LOG_TO_LOGSERVER + */ +public class CmdSysLogTest { + public static Server server = new Server(); + public static SubClient client = new SubClientImpl("127.0.0.1", 10000, UserAgentUtils.createSubUserAgent()); + + @BeforeClass + public static void before_Cmd_syslog() throws Exception { + server.startAccessServer(); + client.init(); + } + + @AfterClass + public static void after_Cmd_syslog() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } + + @Test + public void test_Cmd_syslog() throws Exception { + client.registerBusiHandler(new ReceiveMsgHook() { + @Override + public void handle(Package msg, ChannelHandlerContext ctx) { + System.err.println("receive response from server:------------------" + msg.toString()); + Assert.assertTrue("receive a error command", false); + } + }); +// client.sysLog(); + Thread.sleep(1000); + } +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdTraceLogTest.java b/eventmesh-runtime/src/test/java/protocol/CmdTraceLogTest.java new file mode 100644 index 0000000000..328e13d7ac --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdTraceLogTest.java @@ -0,0 +1,64 @@ +/* + * 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 protocol; + +import client.SubClient; +import client.common.Server; +import client.common.UserAgentUtils; +import client.hook.ReceiveMsgHook; +import client.impl.SubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import io.netty.channel.ChannelHandlerContext; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Cmd Test: TRACE_LOG_TO_LOGSERVER + */ +public class CmdTraceLogTest { + + public static Server server = new Server(); + public static SubClient client = new SubClientImpl("127.0.0.1", 10000, UserAgentUtils.createSubUserAgent()); + + @BeforeClass + public static void before_Cmd_traceLog() throws Exception { + server.startAccessServer(); + client.init(); + } + + @AfterClass + public static void after_Cmd_traceLog() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } + + @Test + public void test_Cmd_traceLog() throws Exception { + client.registerBusiHandler(new ReceiveMsgHook() { + @Override + public void handle(Package msg, ChannelHandlerContext ctx) { + System.err.println("receive response from server:------------------" + msg.toString()); + Assert.assertTrue("receive a error command", false); + } + }); +// client.traceLog(); + Thread.sleep(1000); + } +} diff --git a/eventmesh-runtime/src/test/java/protocol/CmdUnSubscribeTest.java b/eventmesh-runtime/src/test/java/protocol/CmdUnSubscribeTest.java new file mode 100644 index 0000000000..bf9bfbe778 --- /dev/null +++ b/eventmesh-runtime/src/test/java/protocol/CmdUnSubscribeTest.java @@ -0,0 +1,60 @@ +/* + * 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 protocol; + +import client.SubClient; +import client.common.Server; +import client.common.UserAgentUtils; +import client.impl.SubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test Cmd: UNSUBSCRIBE_REQUEST + */ +public class CmdUnSubscribeTest { + + public static Server server = new Server(); + public static SubClient client = new SubClientImpl("127.0.0.1", 10000, UserAgentUtils.createSubUserAgent()); + + @BeforeClass + public static void before_Cmd_unsubscribe() throws Exception { + server.startAccessServer(); + client.init(); + Thread.sleep(1000); + } + + @AfterClass + public static void after_Cmd_unsubscribe() throws Exception { +// server.shutdownAccessServer(); +// client.close(); + } + + @Test + public void test_Cmd_unsubscribe() throws Exception { + Package replyMsg = client.justUnsubscribe("FT0-s-80000000-01-0"); + System.err.println("Reply Message-----------------------------------------" + replyMsg.toString()); + if (replyMsg.getHeader().getCommand() != Command.UNSUBSCRIBE_RESPONSE) { + Assert.assertTrue("UNSUBSCRIBE_RESPONSE FAIL", false); + } + } +} diff --git a/eventmesh-runtime/src/test/java/test/BasicTest.java b/eventmesh-runtime/src/test/java/test/BasicTest.java new file mode 100644 index 0000000000..a78fefd047 --- /dev/null +++ b/eventmesh-runtime/src/test/java/test/BasicTest.java @@ -0,0 +1,159 @@ +/* + * 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 test; + +import client.ProxyClient; +import client.PubClient; +import client.SubClient; +import client.common.MessageUtils; +import client.hook.ReceiveMsgHook; +import client.impl.ProxyClientImpl; +import client.impl.PubClientImpl; +import client.impl.SubClientImpl; +import cn.webank.eventmesh.common.protocol.tcp.AccessMessage; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import io.netty.channel.ChannelHandlerContext; +import org.junit.Test; + +public class BasicTest { + @Test + public void helloTest() throws Exception { + ProxyClient client = initClient(); + client.heartbeat(); + client.close(); + } + + @Test + public void heartbeatTest() throws Exception { + ProxyClient client = initClient(); + client.heartbeat(); + Thread.sleep(4000); + client.close(); + } + + @Test + public void goodbyeTest() throws Exception { + ProxyClient client = initClient(); + client.heartbeat(); + client.goodbye(); + client.close(); + } + + @Test + public void subscribe() throws Exception { + ProxyClient client = initClient(); + client.heartbeat(); + client.justSubscribe("FT0-s-80010000-01-1"); + client.close(); + } + + @Test + public void unsubscribe() throws Exception { + ProxyClient client = initClient(); + client.heartbeat(); + client.justSubscribe("FT0-s-80000000-01-0"); + client.listen(); + client.justUnsubscribe("FT0-s-80000000-01-0"); + client.close(); + } + + @Test + public void listenTest() throws Exception { + ProxyClient client = initClient(); + client.heartbeat(); + client.listen(); + client.close(); + } + + @Test + public void syncMessage() throws Exception { + ProxyClient client = initClient(); + client.heartbeat(); + client.justSubscribe("FT0-s-80000000-01-0"); + client.listen(); + for (int i = 0; i < 100; i++) { + Package rr = client.rr(MessageUtils.rrMesssage("FT0-s-80000000-01-0", i), 3000); + if (rr.getBody() instanceof AccessMessage) { + String body = ((AccessMessage) rr.getBody()).getBody(); + System.err.println("rrMessage: " + body + " " + "rr-reply-------------------------------------------------" + rr.toString()); + } + } + Thread.sleep(100); + client.close(); + } + + @Test + public void asyncMessage() throws Exception { + ProxyClient client = initClient(); + + client.justSubscribe("FT0-e-80010000-01-1"); + client.heartbeat(); + client.listen(); + client.registerSubBusiHandler(new ReceiveMsgHook() { + @Override + public void handle(Package msg, ChannelHandlerContext ctx) { + if (msg.getBody() instanceof AccessMessage) { + String body = ((AccessMessage) msg.getBody()).getBody(); + System.err.println("receive message :------" + body + "------------------------------------------------" + msg.toString()); + } + } + }); + System.err.println("before publish"); + client.publish(MessageUtils.asyncMessage("FT0-e-80010000-01-1", 0), 3000); + Thread.sleep(500); + client.close(); + } + + @Test + public void broadcastMessage() throws Exception { + ProxyClient client = initClient(); + client.heartbeat(); + client.justSubscribe("FT0-e-80030000-01-3"); + client.listen(); + client.registerSubBusiHandler(new ReceiveMsgHook() { + @Override + public void handle(Package msg, ChannelHandlerContext ctx) { + if (msg.getBody() instanceof AccessMessage) { + String body = ((AccessMessage) msg.getBody()).getBody(); + System.err.println("receive message: ------------" + body + "-------------------------------" + msg.toString()); + } + } + }); + client.broadcast(MessageUtils.broadcastMessage("FT0-e-80030000-01-3", 0), 3000); + Thread.sleep(500); + client.close(); + } + + private PubClient initPubClient() throws Exception { + PubClientImpl pubClient = new PubClientImpl("127.0.0.1", 10000, MessageUtils.generatePubClient()); + pubClient.init(); + return pubClient; + } + + private SubClient initSubClient() throws Exception { + SubClientImpl subClient = new SubClientImpl("127.0.0.1", 10000, MessageUtils.generateSubServer()); + subClient.init(); + return subClient; + } + + private ProxyClient initClient() throws Exception { + ProxyClientImpl client = new ProxyClientImpl("127.0.0.1", 10000); + client.init(); + return client; + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/AbstractLiteClient.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/AbstractLiteClient.java new file mode 100644 index 0000000000..5b9e9d1b4e --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/AbstractLiteClient.java @@ -0,0 +1,171 @@ +/* + * 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 cn.webank.eventmesh.client.http; + +import cn.webank.eventmesh.client.http.conf.LiteClientConfig; +import cn.webank.eventmesh.client.http.http.HttpUtil; +import cn.webank.eventmesh.client.http.http.RequestParam; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.ProxyException; +import cn.webank.eventmesh.common.ThreadPoolFactory; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import io.netty.handler.codec.http.HttpMethod; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.RandomUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public abstract class AbstractLiteClient { + + public Logger logger = LoggerFactory.getLogger(AbstractLiteClient.class); + + private static CloseableHttpClient wpcli = HttpClients.createDefault(); + + public LiteClientConfig liteClientConfig; + + private String PROXY_SERVER_KEY = "proxyIpList"; + + public static final String REGEX_VALIDATE_FOR_RPOXY_4_REGION = + "^(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:\\d{4,5}\\|[0-9a-zA-Z]{1,15};)*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:\\d{4,5}\\|[0-9a-zA-Z]{1,15})$"; + + public static final String REGEX_VALIDATE_FOR_RPOXY_DEFAULT = + "^(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:\\d{4,5};)*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:\\d{4,5})$"; + + public Map> regionsMap = Maps.newConcurrentMap(); + + public List forwardAgentList = Lists.newArrayList(); + + private static ScheduledExecutorService scheduledExecutor = + ThreadPoolFactory.createSingleScheduledExecutor("proxy-fetcher-"); + + public AbstractLiteClient(LiteClientConfig liteClientConfig) { + this.liteClientConfig = liteClientConfig; + } + + public void start() throws ProxyException { + if (!liteClientConfig.isRegistryEnabled()) { + String servers = liteClientConfig.getLiteProxyAddr(); + regionsMap = process(servers); + return; + } + + regionsMap = process(loadProxyServers()); + scheduledExecutor.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + try { + regionsMap = process(loadProxyServers()); + } catch (ProxyException lse) { + logger.error("load proxy server err", lse); + } + } + }, 0, liteClientConfig.getRegistryFetchIntervel(), TimeUnit.MILLISECONDS); + + if (StringUtils.isNotBlank(liteClientConfig.getForwardAgents())) { + for (String forwardAgent : liteClientConfig.getForwardAgents().split(";")) { + String host = StringUtils.split(forwardAgent, ":")[0]; + String port = StringUtils.split(forwardAgent, ":")[1]; + forwardAgentList.add(new HttpHost(host, Integer.valueOf(port), "http")); + } + } + } + + public String loadProxyServers() throws ProxyException { + RequestParam requestParam = new RequestParam(HttpMethod.GET); + String servers = ""; + try { + servers = HttpUtil.get(wpcli, + String.format("%s/%s", liteClientConfig.getRegistryAddr(), PROXY_SERVER_KEY) + , requestParam); + } catch (Exception ex) { + throw new ProxyException("load proxy server err", ex); + } + return servers; + } + + private Map process(String format) { + if (format.matches(REGEX_VALIDATE_FOR_RPOXY_4_REGION)) { + Map> tmp = Maps.newConcurrentMap(); + if (StringUtils.isNotBlank(format)) { + String[] serversArr = StringUtils.split(format, ";"); + for (String sin : serversArr) { + String ser = StringUtils.trim(StringUtils.split(sin, "|")[0]); + String region = StringUtils.trim(StringUtils.split(sin, "|")[1]); + if (tmp.containsKey(region)) { + tmp.get(region).add(ser); + } else { + List list = new ArrayList<>(); + list.add(ser); + tmp.put(region, list); + } + } + } + return tmp; + } + + if (format.matches(REGEX_VALIDATE_FOR_RPOXY_DEFAULT)) { + List list = Lists.newArrayList(); + if (StringUtils.isNotBlank(format)) { + String[] serversArr = StringUtils.split(format, ";"); + if (ArrayUtils.isNotEmpty(serversArr)) { + for (String server : serversArr) { + list.add(server); + } + } + } + + Map tmp = Maps.newConcurrentMap(); + tmp.put(Constants.CONSTANTS_DEFAULT_REGION_KEY, list); + return tmp; + } + + logger.error("servers is bad format, servers:{}", format); + return null; + } + + public LiteClientConfig getLiteClientConfig() { + return liteClientConfig; + } + + public List getAvailableServers(String region) { + if (regionsMap.containsKey(region)) { + return regionsMap.get(region); + } + + return regionsMap.get(Constants.CONSTANTS_DEFAULT_REGION_KEY); + } + + public HttpHost getAvailablesForwardAgent() { + return forwardAgentList.get(RandomUtils.nextInt(0, forwardAgentList.size())); + } + + public void shutdown() throws Exception { + scheduledExecutor.shutdown(); + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/ProxyRetObj.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/ProxyRetObj.java new file mode 100644 index 0000000000..2c6f6b1f32 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/ProxyRetObj.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.webank.eventmesh.client.http; + +public class ProxyRetObj { + + private long resTime; + + private int retCode; + + private String retMsg; + + public long getResTime() { + return resTime; + } + + public void setResTime(long resTime) { + this.resTime = resTime; + } + + public int getRetCode() { + return retCode; + } + + public void setRetCode(int retCode) { + this.retCode = retCode; + } + + public String getRetMsg() { + return retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/RemotingServer.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/RemotingServer.java new file mode 100644 index 0000000000..d63aea6d98 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/RemotingServer.java @@ -0,0 +1,424 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/RemotingServer.java +package cn.webank.eventmesh.client.http; +import cn.webank.eventmesh.client.http.consumer.HandleResult; +import cn.webank.eventmesh.client.http.consumer.context.LiteConsumeContext; +import cn.webank.eventmesh.client.http.consumer.listener.LiteMessageListener; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.LiteMessage; +import cn.webank.eventmesh.common.ThreadUtil; +import cn.webank.eventmesh.common.command.HttpCommand; +import cn.webank.eventmesh.common.protocol.http.body.Body; +import cn.webank.eventmesh.common.protocol.http.body.message.PushMessageRequestBody; +import cn.webank.eventmesh.common.protocol.http.common.ClientRetCode; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +import cn.webank.eventmesh.common.protocol.http.header.Header; +import cn.webank.eventmesh.common.protocol.http.header.message.PushMessageRequestHeader; +======== +package org.apache.eventmesh.client.http; +import org.apache.eventmesh.client.http.consumer.HandleResult; +import org.apache.eventmesh.client.http.consumer.context.LiteConsumeContext; +import org.apache.eventmesh.client.http.consumer.listener.LiteMessageListener; +import com.webank.eventmesh.common.Constants; +import com.webank.eventmesh.common.IPUtil; +import com.webank.eventmesh.common.LiteMessage; +import com.webank.eventmesh.common.ThreadUtil; +import com.webank.eventmesh.common.command.HttpCommand; +import com.webank.eventmesh.common.protocol.http.body.Body; +import com.webank.eventmesh.common.protocol.http.body.message.PushMessageRequestBody; +import com.webank.eventmesh.common.protocol.http.common.ClientRetCode; +import com.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import com.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +import com.webank.eventmesh.common.protocol.http.header.Header; +import com.webank.eventmesh.common.protocol.http.header.message.PushMessageRequestHeader; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/RemotingServer.java +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.*; +import io.netty.handler.codec.http.multipart.Attribute; +import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; +import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; +import io.netty.handler.codec.http.multipart.InterfaceHttpData; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.RandomUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +public class RemotingServer { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public AtomicBoolean started = new AtomicBoolean(Boolean.FALSE); + + public AtomicBoolean inited = new AtomicBoolean(Boolean.FALSE); + + private EventLoopGroup bossGroup; + + private EventLoopGroup workerGroup; + + private int port = RandomUtils.nextInt(1000, 20000); + + private DefaultHttpDataFactory defaultHttpDataFactory = new DefaultHttpDataFactory(false); + + private ThreadPoolExecutor consumeExecutor; + + private LiteMessageListener messageListener; + + public RemotingServer() { + } + + public RemotingServer(int port) { + this.port = port; + } + + public RemotingServer(ThreadPoolExecutor consumeExecutor) { + this.consumeExecutor = consumeExecutor; + } + + public RemotingServer(int port, ThreadPoolExecutor consumeExecutor) { + this.port = port; + this.consumeExecutor = consumeExecutor; + } + + public void setPort(int port) { + this.port = port; + } + + public void setConsumeExecutor(ThreadPoolExecutor consumeExecutor) { + this.consumeExecutor = consumeExecutor; + } + + public void registerMessageListener(LiteMessageListener proxyMessageListener) { + this.messageListener = proxyMessageListener; + } + + private EventLoopGroup initBossGroup() { + bossGroup = new NioEventLoopGroup(1, new ThreadFactory() { + AtomicInteger count = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, "endPointBoss-" + count.incrementAndGet()); + t.setDaemon(true); + return t; + } + }); + + return bossGroup; + } + + private EventLoopGroup initWokerGroup() { + workerGroup = new NioEventLoopGroup(2, new ThreadFactory() { + AtomicInteger count = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, "endpointWorker-" + count.incrementAndGet()); + return t; + } + }); + return workerGroup; + } + + public String getEndpointURL() { + return String.format("http://%s:%s", IPUtil.getLocalAddress(), port); + } + + class HTTPHandler extends SimpleChannelInboundHandler { + + /** + * 解析请求HEADER + * + * @param fullReq + * @return + */ + private Map parseHTTPHeader(HttpRequest fullReq) { + Map headerParam = new HashMap<>(); + for (String key : fullReq.headers().names()) { + if (StringUtils.equalsIgnoreCase(HttpHeaderNames.CONTENT_TYPE.toString(), key) + || StringUtils.equalsIgnoreCase(HttpHeaderNames.ACCEPT_ENCODING.toString(), key) + || StringUtils.equalsIgnoreCase(HttpHeaderNames.CONTENT_LENGTH.toString(), key)) { + continue; + } + headerParam.put(key, fullReq.headers().get(key)); + } + return headerParam; + } + + @Override + protected void channelRead0(final ChannelHandlerContext ctx, HttpRequest httpRequest) throws Exception { + HttpPostRequestDecoder decoder = null; + try { + if (!httpRequest.decoderResult().isSuccess()) { + sendError(ctx, HttpResponseStatus.BAD_REQUEST); + return; + } + + //协议版本核查 + String protocolVersion = StringUtils.deleteWhitespace(httpRequest.headers().get(ProtocolKey.VERSION)); + if (StringUtils.isBlank(protocolVersion) || !ProtocolVersion.contains(protocolVersion)) { + httpRequest.headers().set(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()); + } + + Map bodyMap = new HashMap<>(); + + if (httpRequest.method() == HttpMethod.GET) { + QueryStringDecoder getDecoder = new QueryStringDecoder(httpRequest.uri()); + for (Map.Entry> entry : getDecoder.parameters().entrySet()) { + bodyMap.put(entry.getKey(), entry.getValue().get(0)); + } + } else if (httpRequest.method() == HttpMethod.POST) { + decoder = new HttpPostRequestDecoder(defaultHttpDataFactory, httpRequest); + List parmList = decoder.getBodyHttpDatas(); + for (InterfaceHttpData parm : parmList) { + if (parm.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) { + Attribute data = (Attribute) parm; + bodyMap.put(data.getName(), data.getValue()); + } + } + } else { + sendError(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED); + return; + } + + /////////////////////////////////////////////////////////////////基础检查//////////////////////////////////////////////////// + String requestCode = + (httpRequest.method() == HttpMethod.POST) ? StringUtils.deleteWhitespace(httpRequest.headers().get(ProtocolKey.REQUEST_CODE)) + : MapUtils.getString(bodyMap, StringUtils.lowerCase(ProtocolKey.REQUEST_CODE), ""); + + final HttpCommand requestCommand = new HttpCommand( + httpRequest.method().name(), + httpRequest.protocolVersion().protocolName(), requestCode); + + HttpCommand responseCommand; + + //校验requestCode + if (StringUtils.isBlank(requestCode) + || !StringUtils.isNumeric(requestCode) + || (!String.valueOf(RequestCode.HTTP_PUSH_CLIENT_ASYNC.getRequestCode()).equals(requestCode) + && !String.valueOf(RequestCode.HTTP_PUSH_CLIENT_SYNC.getRequestCode()).equals(requestCode))) { + logger.error("receive invalid requestCode, {}", requestCode); + responseCommand = requestCommand.createHttpCommandResponse(ClientRetCode.OK.getRetCode(), ClientRetCode.OK.getErrMsg()); + sendResponse(ctx, responseCommand.httpResponse()); + return; + } + + requestCommand.setHeader(Header.buildHeader(requestCode, parseHTTPHeader(httpRequest))); + requestCommand.setBody(Body.buildBody(requestCode, bodyMap)); + + if (logger.isDebugEnabled()) { + logger.debug("{}", requestCommand); + } + + PushMessageRequestHeader pushMessageRequestHeader = (PushMessageRequestHeader) requestCommand.header; + PushMessageRequestBody pushMessageRequestBody = (PushMessageRequestBody) requestCommand.body; + + String topic = pushMessageRequestBody.getTopic(); + + //检查是否有该TOPIC的listener +// if (!listenerTable.containsKey(topic)) { +// logger.error("no listenning for this topic, {}", pushMessageRequest); +// responseCommand = requestCommand.createHttpCommandResponse(ClientRetCode.NOLISTEN.getRetCode(), ClientRetCode.NOLISTEN.getErrMsg()); +// sendResponse(ctx, responseCommand.httpResponse()); +// return; +// } + + final LiteConsumeContext proxyConsumeContext = new LiteConsumeContext(pushMessageRequestHeader.getProxyIp(), + pushMessageRequestHeader.getProxyEnv(), pushMessageRequestHeader.getProxyIdc(), + pushMessageRequestHeader.getProxyRegion(), + pushMessageRequestHeader.getProxyCluster(), pushMessageRequestHeader.getProxyDcn()); + + final LiteMessage liteMessage = new LiteMessage(pushMessageRequestBody.getBizSeqNo(), pushMessageRequestBody.getUniqueId(), + topic, pushMessageRequestBody.getContent()); + + for (Map.Entry entry : pushMessageRequestBody.getExtFields().entrySet()) { + liteMessage.addProp(entry.getKey(), entry.getValue()); + } + + //转交到消费线程池中 + consumeExecutor.execute(new Runnable() { + @Override + public void run() { + try { + if (messageListener.reject()) { + HttpCommand responseCommand = requestCommand.createHttpCommandResponse(handleResult2ClientRetCode(HandleResult.RETRY).getRetCode(), handleResult2ClientRetCode(HandleResult.RETRY).getErrMsg()); + sendResponse(ctx, responseCommand.httpResponse()); + return; + } + + HandleResult handleResult = messageListener.handle(liteMessage, proxyConsumeContext); + + if (logger.isDebugEnabled()) { + logger.info("bizSeqNo:{}, topic:{}, handleResult:{}", liteMessage.getBizSeqNo(), liteMessage.getTopic(), handleResult); + } + + HttpCommand responseCommand = requestCommand.createHttpCommandResponse(handleResult2ClientRetCode(handleResult).getRetCode(), handleResult2ClientRetCode(handleResult).getErrMsg()); + sendResponse(ctx, responseCommand.httpResponse()); + } catch (Exception e) { + logger.error("process error", e); + } + } + }); + } catch (Exception ex) { + logger.error("HTTPHandler.channelRead0 err", ex); + } finally { + try { + decoder.destroy(); + } catch (Exception e) { + } + } + } + + public ClientRetCode handleResult2ClientRetCode(HandleResult handleResult) { + if (handleResult == HandleResult.OK) { + return ClientRetCode.OK; + } else if (handleResult == HandleResult.FAIL) { + return ClientRetCode.FAIL; + } else if (handleResult == HandleResult.NOLISTEN) { + return ClientRetCode.NOLISTEN; + } else if (handleResult == HandleResult.RETRY) { + return ClientRetCode.RETRY; + } else { + return ClientRetCode.OK; + } + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + super.channelReadComplete(ctx); + ctx.flush(); // 4 + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + if (null != cause) cause.printStackTrace(); + if (null != ctx) ctx.close(); + } + + /** + * 默认错误页面发送 + * + * @param ctx + * @param status + */ + private void sendError(ChannelHandlerContext ctx, + HttpResponseStatus status) { + FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, + status); + response.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN + + "; charset=" + Constants.DEFAULT_CHARSET); + response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); + response.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + } + + + /** + * 发送响应 + * + * @param ctx + * @param response + */ + private void sendResponse(ChannelHandlerContext ctx, + DefaultFullHttpResponse response) { + ctx.writeAndFlush(response).addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture f) throws Exception { + if (!f.isSuccess()) { + logger.warn("send response to [{}] fail, will close this channel", IPUtil.parseChannelRemoteAddr(f.channel())); + f.channel().close(); + return; + } + } + }); + } + + public void init() throws Exception { + initBossGroup(); + initWokerGroup(); + inited.compareAndSet(false, true); + } + + public void shutdown() throws Exception { + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + } + + ThreadUtil.randomSleep(30); + + if (workerGroup != null) { + workerGroup.shutdownGracefully(); + } + + started.compareAndSet(true, false); + inited.compareAndSet(true, false); + } + + public void start() throws Exception { + Runnable r = new Runnable() { + @Override + public void run() { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) + throws Exception { + ch.pipeline() + .addLast(new HttpRequestDecoder(), + new HttpResponseEncoder(), + new HttpObjectAggregator(Integer.MAX_VALUE), + new HTTPHandler()); // 4 + } + }).childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE); + try { + logger.info("WeMQProxy Client[{}] Started......", port); + ChannelFuture future = b.bind(port).sync(); + future.channel().closeFuture().sync(); + started.compareAndSet(false, true); + } catch (Exception e) { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + }; + + + Thread t = new Thread(r, "proxy-client-remoting-server"); + t.start(); + } + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/conf/LiteClientConfig.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/conf/LiteClientConfig.java new file mode 100644 index 0000000000..69a1147849 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/conf/LiteClientConfig.java @@ -0,0 +1,231 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/conf/LiteClientConfig.java +package cn.webank.eventmesh.client.http.conf; + +import com.google.common.base.Preconditions; +import org.apache.commons.lang3.StringUtils; +======== +package org.apache.eventmesh.client.http.conf; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/conf/LiteClientConfig.java + +public class LiteClientConfig { + + private String liteProxyAddr = "127.0.0.1:10105"; + + private String forwardAgents = "127.0.0.1:3128"; + + private boolean registryEnabled = Boolean.FALSE; + + private String registryAddr = "http://127.0.0.1:8090"; + + private int registryFetchIntervel = 30000; + + private int consumeThreadCore = 2; + + private int consumeThreadMax = 5; + + private String env; + + private String region; + + private String idc; + + private String dcn; + + private String ip = "127.0.0.1"; + + private String pid; + + private String sys; + + private String userName = "wemq"; + + private String password = "wemq@123"; + + public int getConsumeThreadMax() { + return consumeThreadMax; + } + + public LiteClientConfig setConsumeThreadMax(int consumeThreadMax) { + this.consumeThreadMax = consumeThreadMax; + return this; + } + + public String getForwardAgents() { + return forwardAgents; + } + + public LiteClientConfig setForwardAgents(String forwardAgents) { + this.forwardAgents = forwardAgents; + return this; + } + + public int getConsumeThreadCore() { + return consumeThreadCore; + } + + public LiteClientConfig setConsumeThreadCore(int consumeThreadCore) { + this.consumeThreadCore = consumeThreadCore; + return this; + } + + public String getEnv() { + return env; + } + + public LiteClientConfig setEnv(String env) { + this.env = env; + return this; + } + + public String getRegion() { + return region; + } + + public LiteClientConfig setRegion(String region) { + this.region = region; + return this; + } + + public String getIdc() { + return idc; + } + + public LiteClientConfig setIdc(String idc) { + this.idc = idc; + return this; + } + + public String getDcn() { + return dcn; + } + + public LiteClientConfig setDcn(String dcn) { + this.dcn = dcn; + return this; + } + + public String getIp() { + return ip; + } + + public LiteClientConfig setIp(String ip) { + this.ip = ip; + return this; + } + + public String getPid() { + return pid; + } + + public LiteClientConfig setPid(String pid) { + this.pid = pid; + return this; + } + + public String getSys() { + return sys; + } + + public LiteClientConfig setSys(String sys) { + this.sys = sys; + return this; + } + + public String getUserName() { + return userName; + } + + public LiteClientConfig setUserName(String userName) { + this.userName = userName; + return this; + } + + public String getPassword() { + return password; + } + + public LiteClientConfig setPassword(String password) { + this.password = password; + return this; + } + + public String getLiteProxyAddr() { + return liteProxyAddr; + } + + public LiteClientConfig setLiteProxyAddr(String liteProxyAddr) { + this.liteProxyAddr = liteProxyAddr; + return this; + } + + public boolean isRegistryEnabled() { + return registryEnabled; + } + + public LiteClientConfig setRegistryEnabled(boolean registryEnabled) { + this.registryEnabled = registryEnabled; + return this; + } + + public String getRegistryAddr() { + return registryAddr; + } + + public LiteClientConfig setRegistryAddr(String registryAddr) { + this.registryAddr = registryAddr; + return this; + } + + public int getRegistryFetchIntervel() { + return registryFetchIntervel; + } + + public LiteClientConfig setRegistryFetchIntervel(int registryFetchIntervel) { + this.registryFetchIntervel = registryFetchIntervel; + return this; + } + + public void validate() throws IllegalStateException { + Preconditions.checkState((registryEnabled && StringUtils.isNotBlank(registryAddr)) + || (!registryEnabled && StringUtils.isNotBlank(liteProxyAddr)), "liteClientConfig[registryEnabled/registryAddr/liteServerAddr] invalid"); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("liteClientConfig={") + .append("liteProxyAddr=").append(liteProxyAddr).append(",") + .append("registryEnabled=").append(registryEnabled).append(",") + .append("registryAddr=").append(registryAddr).append(",") + .append("registryFetchIntervel=").append(registryFetchIntervel).append(",") + .append("consumeThreadCore=").append(consumeThreadCore).append(",") + .append("consumeThreadMax=").append(consumeThreadMax).append(",") + .append("env=").append(env).append(",") + .append("region=").append(region).append(",") + .append("idc=").append(idc).append(",") + .append("dcn=").append(dcn).append(",") + .append("ip=").append(ip).append(",") + .append("pid=").append(pid).append(",") + .append("sys=").append(sys).append(",") + .append("userName=").append(userName).append(",") + .append("password=").append(password).append("}"); + return sb.toString(); + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/HandleResult.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/HandleResult.java new file mode 100644 index 0000000000..b7f1f9dff5 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/HandleResult.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/HandleResult.java +package cn.webank.eventmesh.client.http.consumer; +======== +package org.apache.eventmesh.client.http.consumer; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/consumer/HandleResult.java + +public enum HandleResult { + OK, + NOLISTEN, + RETRY, + FAIL +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/LiteConsumer.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/LiteConsumer.java new file mode 100644 index 0000000000..4242fe2456 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/LiteConsumer.java @@ -0,0 +1,104 @@ +/* + * 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 cn.webank.eventmesh.client.http.consumer; + +import cn.webank.eventmesh.client.http.AbstractLiteClient; +import cn.webank.eventmesh.client.http.RemotingServer; +import cn.webank.eventmesh.client.http.conf.LiteClientConfig; +import cn.webank.eventmesh.client.http.consumer.listener.LiteMessageListener; +import cn.webank.eventmesh.common.ProxyException; +import cn.webank.eventmesh.common.ThreadPoolFactory; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicBoolean; + +public class LiteConsumer extends AbstractLiteClient { + + public Logger logger = LoggerFactory.getLogger(LiteConsumer.class); + + private RemotingServer remotingServer; + + private ThreadPoolExecutor consumeExecutor; + + private static CloseableHttpClient httpClient = HttpClients.createDefault(); + + protected LiteClientConfig weMQProxyClientConfig; + + private List subscription = Lists.newArrayList(); + + private LiteMessageListener messageListener; + + public LiteConsumer(LiteClientConfig liteClientConfig) { + super(liteClientConfig); + this.consumeExecutor = ThreadPoolFactory.createThreadPoolExecutor(weMQProxyClientConfig.getConsumeThreadCore(), + weMQProxyClientConfig.getConsumeThreadMax(), "proxy-client-consume-"); + this.remotingServer = new RemotingServer(consumeExecutor); + } + + public LiteConsumer(LiteClientConfig liteClientConfig, + ThreadPoolExecutor customExecutor) { + super(liteClientConfig); + this.consumeExecutor = customExecutor; + this.remotingServer = new RemotingServer(this.consumeExecutor); + } + + private AtomicBoolean started = new AtomicBoolean(Boolean.FALSE); + + public void start() throws ProxyException { + Preconditions.checkState(weMQProxyClientConfig != null, "weMQProxyClientConfig can't be null"); + Preconditions.checkState(consumeExecutor != null, "consumeExecutor can't be null"); + Preconditions.checkState(messageListener != null, "messageListener can't be null"); + logger.info("LiteConsumer starting"); + super.start(); + started.compareAndSet(false, true); + logger.info("LiteConsumer started"); + } + + public void shutdown() throws Exception { + logger.info("LiteConsumer shutting down"); + super.shutdown(); + httpClient.close(); + started.compareAndSet(true, false); + logger.info("LiteConsumer shutdown"); + } + + + public boolean subscribe(String topic) throws ProxyException { + subscription.add(topic); + //做一次心跳 + return Boolean.TRUE; + } + + public boolean unsubscribe(String topic) throws ProxyException { + subscription.remove(topic); + //做一次心跳 + return Boolean.TRUE; + } + + public void registerMessageListener(LiteMessageListener messageListener) throws ProxyException { + this.messageListener = messageListener; + remotingServer.registerMessageListener(this.messageListener); + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/context/LiteConsumeContext.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/context/LiteConsumeContext.java new file mode 100644 index 0000000000..564b5ec43f --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/context/LiteConsumeContext.java @@ -0,0 +1,126 @@ +/* + * 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 cn.webank.eventmesh.client.http.consumer.context; + +import cn.webank.eventmesh.common.Constants; +import org.apache.commons.lang3.time.DateFormatUtils; + +public class LiteConsumeContext { + + private String proxyIp; + + private String proxyEnv; + + private String proxyRegion; + + private String proxyIdc; + + private String proxyCluster; + + private String proxyDcn; + + //本地RETRY次数 + private int retryTimes = 0; + + private long createTime = System.currentTimeMillis(); + + public LiteConsumeContext(String proxyIp, String proxyEnv, + String proxyIdc, String proxyRegion, + String proxyCluster, String proxyDcn) { + this.proxyIp = proxyIp; + this.proxyEnv = proxyEnv; + this.proxyIdc = proxyIdc; + this.proxyRegion = proxyRegion; + this.proxyCluster = proxyCluster; + this.proxyDcn = proxyDcn; + + } + + public String getProxyIp() { + return proxyIp; + } + + public void setProxyIp(String proxyIp) { + this.proxyIp = proxyIp; + } + + public String getProxyEnv() { + return proxyEnv; + } + + public void setProxyEnv(String proxyEnv) { + this.proxyEnv = proxyEnv; + } + + public String getProxyIdc() { + return proxyIdc; + } + + public void setProxyIdc(String proxyIdc) { + this.proxyIdc = proxyIdc; + } + + public String getProxyCluster() { + return proxyCluster; + } + + public void setProxyCluster(String proxyCluster) { + this.proxyCluster = proxyCluster; + } + + public String getProxyDcn() { + return proxyDcn; + } + + public void setProxyDcn(String proxyDcn) { + this.proxyDcn = proxyDcn; + } + + public String getProxyRegion() { + return proxyRegion; + } + + public void setProxyRegion(String proxyRegion) { + this.proxyRegion = proxyRegion; + } + + public int getRetryTimes() { + return retryTimes; + } + + public void setRetryTimes(int retryTimes) { + this.retryTimes = retryTimes; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("liteConsumeContext={") + .append("proxyIp=").append(proxyIp).append(",") + .append("proxyEnv=").append(proxyEnv).append(",") + .append("proxyRegion=").append(proxyRegion).append(",") + .append("proxyIdc=").append(proxyIdc).append(",") + .append("proxyCluster=").append(proxyCluster).append(",") + .append("proxyDcn=").append(proxyDcn).append(",") + .append("retryTimes=").append(retryTimes).append(",") + .append("createTime=").append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT)) + .append("}"); + return sb.toString(); + } + +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/listener/LiteMessageListener.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/listener/LiteMessageListener.java new file mode 100644 index 0000000000..f1a225e23c --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/listener/LiteMessageListener.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/consumer/listener/LiteMessageListener.java +package cn.webank.eventmesh.client.http.consumer.listener; + +import cn.webank.eventmesh.client.http.consumer.HandleResult; +import cn.webank.eventmesh.client.http.consumer.context.LiteConsumeContext; +import cn.webank.eventmesh.common.LiteMessage; +======== +package org.apache.eventmesh.client.http.consumer.listener; + +import org.apache.eventmesh.client.http.consumer.HandleResult; +import org.apache.eventmesh.client.http.consumer.context.LiteConsumeContext; +import com.webank.eventmesh.common.LiteMessage; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/consumer/listener/LiteMessageListener.java + +public interface LiteMessageListener { + + HandleResult handle(LiteMessage liteMessage, LiteConsumeContext liteConsumeContext); + + boolean reject(); + +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/http/HttpUtil.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/http/HttpUtil.java new file mode 100644 index 0000000000..709ac3a3ff --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/http/HttpUtil.java @@ -0,0 +1,256 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/http/HttpUtil.java +package cn.webank.eventmesh.client.http.http; +import cn.webank.eventmesh.common.Constants; +======== +package org.apache.eventmesh.client.http.http; +import com.webank.eventmesh.common.Constants; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/http/HttpUtil.java +import com.google.common.base.Preconditions; +import io.netty.handler.codec.http.HttpMethod; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class HttpUtil { + + public static Logger logger = LoggerFactory.getLogger(HttpUtil.class); + + public static String post(CloseableHttpClient client, + String uri, + RequestParam requestParam) throws Exception { + final ResponseHolder responseHolder = new ResponseHolder(); + final CountDownLatch countDownLatch = new CountDownLatch(1); + post(client, null, uri, requestParam, new ResponseHandler() { + @Override + public String handleResponse(HttpResponse response) throws IOException { + responseHolder.response = EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET)); + countDownLatch.countDown(); + if (logger.isDebugEnabled()) { + logger.debug("{}", responseHolder); + } + return responseHolder.response; + } + }); + + try { + countDownLatch.await(requestParam.getTimeout(), TimeUnit.MILLISECONDS); + } catch (InterruptedException ie) { + } + + return responseHolder.response; + } + + public static String post(CloseableHttpClient client, + HttpHost forwardAgent, + String uri, + RequestParam requestParam) throws Exception { + final ResponseHolder responseHolder = new ResponseHolder(); + final CountDownLatch countDownLatch = new CountDownLatch(1); + post(client, forwardAgent, uri, requestParam, new ResponseHandler() { + @Override + public String handleResponse(HttpResponse response) throws IOException { + responseHolder.response = EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET)); + countDownLatch.countDown(); + if (logger.isDebugEnabled()) { + logger.debug("{}", responseHolder); + } + return responseHolder.response; + } + }); + + try { + countDownLatch.await(requestParam.getTimeout(), TimeUnit.MILLISECONDS); + } catch (InterruptedException ie) { + } + + return responseHolder.response; + } + + public static void post(CloseableHttpClient client, + HttpHost forwardAgent, + String uri, + RequestParam requestParam, + ResponseHandler responseHandler) throws Exception { + Preconditions.checkState(client != null, "client can't be null"); + Preconditions.checkState(StringUtils.isNotBlank(uri), "uri can't be null"); + Preconditions.checkState(requestParam != null, "requestParam can't be null"); + Preconditions.checkState(responseHandler != null, "responseHandler can't be null"); + Preconditions.checkState(requestParam.getHttpMethod() == HttpMethod.POST, "invalid requestParam httpMethod"); + + HttpPost httpPost = new HttpPost(uri); + + //header + if (MapUtils.isNotEmpty(requestParam.getHeaders())) { + for (Map.Entry entry : requestParam.getHeaders().entrySet()) { + httpPost.addHeader(entry.getKey(), entry.getValue()); + } + } + + //body + if (MapUtils.isNotEmpty(requestParam.getBody())) { + List pairs = new ArrayList<>(); + for (Map.Entry entry : requestParam.getBody().entrySet()) { + pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); + } + httpPost.setEntity(new UrlEncodedFormEntity(pairs, Constants.DEFAULT_CHARSET)); + } + + //ttl + RequestConfig.Builder configBuilder = RequestConfig.custom(); + configBuilder.setSocketTimeout(Integer.valueOf(String.valueOf(requestParam.getTimeout()))) + .setConnectTimeout(Integer.valueOf(String.valueOf(requestParam.getTimeout()))) + .setConnectionRequestTimeout(Integer.valueOf(String.valueOf(requestParam.getTimeout()))); + + if(forwardAgent != null) { + configBuilder.setProxy(forwardAgent); + } + + httpPost.setConfig(configBuilder.build()); + + if (logger.isDebugEnabled()) { + logger.debug("{}", httpPost); + } + + client.execute(httpPost, responseHandler); + } + + public static void get(CloseableHttpClient client, + HttpHost forwardAgent, + String uri, + RequestParam requestParam, + ResponseHandler responseHandler) throws Exception { + Preconditions.checkState(client != null, "client can't be null"); + Preconditions.checkState(StringUtils.isNotBlank(uri), "uri can't be null"); + Preconditions.checkState(requestParam != null, "requestParam can't be null"); + Preconditions.checkState(requestParam.getHttpMethod() == HttpMethod.GET, "invalid requestParam httpMethod"); + + //body + if (MapUtils.isNotEmpty(requestParam.getQueryParamsMap())) { + uri = uri + "?" + requestParam.getQueryParams(); + } + + HttpGet httpGet = new HttpGet(uri); + + //header + if (MapUtils.isNotEmpty(requestParam.getHeaders())) { + for (Map.Entry entry : requestParam.getHeaders().entrySet()) { + httpGet.addHeader(entry.getKey(), entry.getValue()); + } + } + + //ttl + RequestConfig.Builder configBuilder = RequestConfig.custom(); + configBuilder.setSocketTimeout(Integer.valueOf(String.valueOf(requestParam.getTimeout()))) + .setConnectTimeout(Integer.valueOf(String.valueOf(requestParam.getTimeout()))) + .setConnectionRequestTimeout(Integer.valueOf(String.valueOf(requestParam.getTimeout()))); + + if(forwardAgent != null) { + configBuilder.setProxy(forwardAgent); + } + + httpGet.setConfig(configBuilder.build()); + + if (logger.isDebugEnabled()) { + logger.debug("{}", httpGet); + } + + client.execute(httpGet, responseHandler); + } + + public static String get(CloseableHttpClient client, + String url, + RequestParam requestParam) throws Exception { + final ResponseHolder responseHolder = new ResponseHolder(); + final CountDownLatch countDownLatch = new CountDownLatch(1); + get(client, null, url, requestParam, new ResponseHandler() { + @Override + public String handleResponse(HttpResponse response) throws IOException { + responseHolder.response = EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET)); + countDownLatch.countDown(); + if (logger.isDebugEnabled()) { + logger.debug("{}", responseHolder); + } + return responseHolder.response; + } + }); + + try { + countDownLatch.await(requestParam.getTimeout(), TimeUnit.MILLISECONDS); + } catch (InterruptedException ie) { + } + + return responseHolder.response; + } + + public static String get(CloseableHttpClient client, + HttpHost forwardAgent, + String url, + RequestParam requestParam) throws Exception { + final ResponseHolder responseHolder = new ResponseHolder(); + final CountDownLatch countDownLatch = new CountDownLatch(1); + get(client, forwardAgent, url, requestParam, new ResponseHandler() { + @Override + public String handleResponse(HttpResponse response) throws IOException { + responseHolder.response = EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET)); + countDownLatch.countDown(); + if (logger.isDebugEnabled()) { + logger.debug("{}", responseHolder); + } + return responseHolder.response; + } + }); + + try { + countDownLatch.await(requestParam.getTimeout(), TimeUnit.MILLISECONDS); + } catch (InterruptedException ie) { + } + + return responseHolder.response; + } + + public static class ResponseHolder { + public String response; + + @Override + public String toString() { + return "ResponseHolder=" + response + ""; + } + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/http/RequestParam.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/http/RequestParam.java new file mode 100644 index 0000000000..3ef87bc1aa --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/http/RequestParam.java @@ -0,0 +1,143 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/http/RequestParam.java +package cn.webank.eventmesh.client.http.http; +======== +package org.apache.eventmesh.client.http.http; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/http/RequestParam.java + +import io.netty.handler.codec.http.HttpMethod; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +public class RequestParam { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + private Map queryParams; + + private HttpMethod httpMethod; + + private Map body; + + private Map headers; + + private long timeout; + + public RequestParam(HttpMethod httpMethod) { + this.httpMethod = httpMethod; + } + + public HttpMethod getHttpMethod() { + return httpMethod; + } + + public Map getHeaders() { + return headers; + } + + public RequestParam setHeaders(Map headers) { + this.headers = headers; + return this; + } + + public Map getBody() { + return body; + } + + public RequestParam setBody(Map body) { + this.body = body; + return this; + } + + public Map getQueryParamsMap() { + return queryParams; + } + + public String getQueryParams() { + if (queryParams == null || queryParams.size() == 0) { + return ""; + } + StringBuilder stringBuilder = new StringBuilder(); + try { + for (Map.Entry query : queryParams.entrySet()) { + for (String val : query.getValue()) { + stringBuilder.append("&") + .append(URLEncoder.encode(query.getKey(), "UTF-8")); + + if (val != null && !val.isEmpty()) { + stringBuilder.append("=") + .append(URLEncoder.encode(val, "UTF-8")); + } + } + } + } catch (UnsupportedEncodingException e) { + logger.error("get query params failed.", e); + return ""; + } + return stringBuilder.substring(1); + } + + public RequestParam setQueryParams(Map queryParams) { + this.queryParams = queryParams; + return this; + } + + public RequestParam addQueryParam(String key, String value) { + if (queryParams == null) { + queryParams = new HashMap<>(); + } + if (!queryParams.containsKey(key)) { + queryParams.put(key, new String[]{value}); + } else { + queryParams.put(key, (String[]) Arrays.asList(queryParams.get(key), value).toArray()); + } + return this; + } + + public RequestParam addHeader(String key, String value) { + if (headers == null) { + headers = new HashMap<>(); + } + headers.put(key, value); + return this; + } + + public RequestParam addBody(String key, String value) { + if (body == null) { + body = new HashMap<>(); + } + body.put(key, value); + return this; + } + + public long getTimeout() { + return timeout; + } + + public RequestParam setTimeout(long timeout) { + this.timeout = timeout; + return this; + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/LiteProducer.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/LiteProducer.java new file mode 100644 index 0000000000..7cfc4c1ba9 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/LiteProducer.java @@ -0,0 +1,269 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/LiteProducer.java +package cn.webank.eventmesh.client.http.producer; + +import cn.webank.eventmesh.client.http.AbstractLiteClient; +import cn.webank.eventmesh.client.http.ProxyRetObj; +import cn.webank.eventmesh.client.http.conf.LiteClientConfig; +import cn.webank.eventmesh.client.http.http.HttpUtil; +import cn.webank.eventmesh.client.http.http.RequestParam; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.LiteMessage; +import cn.webank.eventmesh.common.ProxyException; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import cn.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import cn.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +import cn.webank.eventmesh.common.protocol.http.common.RequestCode; +======== +package org.apache.eventmesh.client.http.producer; + +import org.apache.eventmesh.client.http.AbstractLiteClient; +import org.apache.eventmesh.client.http.EventMeshRetObj; +import org.apache.eventmesh.client.http.conf.LiteClientConfig; +import org.apache.eventmesh.client.http.http.HttpUtil; +import org.apache.eventmesh.client.http.http.RequestParam; +import org.apache.eventmesh.client.http.ssl.MyX509TrustManager; +import com.webank.eventmesh.common.Constants; +import com.webank.eventmesh.common.LiteMessage; +import com.webank.eventmesh.common.EventMeshException; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import com.webank.eventmesh.common.protocol.http.common.ProtocolKey; +import com.webank.eventmesh.common.protocol.http.common.ProtocolVersion; +import com.webank.eventmesh.common.protocol.http.common.EventMeshRetCode; +import com.webank.eventmesh.common.protocol.http.common.RequestCode; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/LiteProducer.java +import com.alibaba.fastjson.JSON; +import com.google.common.base.Preconditions; +import io.netty.handler.codec.http.HttpMethod; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.RandomUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +public class LiteProducer extends AbstractLiteClient { + + public Logger logger = LoggerFactory.getLogger(LiteProducer.class); + + private static CloseableHttpClient httpClient = HttpClients.createDefault(); + + public LiteProducer(LiteClientConfig liteClientConfig) { + super(liteClientConfig); + } + + private AtomicBoolean started = new AtomicBoolean(Boolean.FALSE); + + public void start() throws ProxyException { + Preconditions.checkState(liteClientConfig != null, "liteClientConfig can't be null"); + if(started.get()) { + return; + } + logger.info("LiteProducer starting"); + super.start(); + started.compareAndSet(false, true); + logger.info("LiteProducer started"); + } + + public void shutdown() throws Exception { + if(!started.get()) { + return; + } + logger.info("LiteProducer shutting down"); + super.shutdown(); + httpClient.close(); + started.compareAndSet(true, false); + logger.info("LiteProducer shutdown"); + } + + public AtomicBoolean getStarted() { + return started; + } + + public boolean publish(LiteMessage message) throws ProxyException { + if (!started.get()) { + start(); + } + Preconditions.checkState(StringUtils.isNotBlank(message.getTopic()), + "proxyMessage[topic] invalid"); + Preconditions.checkState(StringUtils.isNotBlank(message.getContent()), + "proxyMessage[content] invalid"); + RequestParam requestParam = new RequestParam(HttpMethod.POST); + requestParam.addHeader(ProtocolKey.REQUEST_CODE, String.valueOf(RequestCode.MSG_SEND_ASYNC.getRequestCode())) + .addHeader(ProtocolKey.ClientInstanceKey.ENV, liteClientConfig.getEnv()) + .addHeader(ProtocolKey.ClientInstanceKey.IDC, liteClientConfig.getIdc()) + .addHeader(ProtocolKey.ClientInstanceKey.IP, liteClientConfig.getIp()) + .addHeader(ProtocolKey.ClientInstanceKey.PID, liteClientConfig.getPid()) + .addHeader(ProtocolKey.ClientInstanceKey.SYS, liteClientConfig.getSys()) + .addHeader(ProtocolKey.ClientInstanceKey.USERNAME, liteClientConfig.getUserName()) + .addHeader(ProtocolKey.ClientInstanceKey.PASSWD, liteClientConfig.getPassword()) + .addHeader(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()) + .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) + .setTimeout(Constants.DEFAULT_HTTP_TIME_OUT) + .addBody(SendMessageRequestBody.PRODUCERGROUP, liteClientConfig.getProducerGroup()) + .addBody(SendMessageRequestBody.TOPIC, message.getTopic()) + .addBody(SendMessageRequestBody.CONTENT, message.getContent()) + .addBody(SendMessageRequestBody.TTL, message.getPropKey(Constants.PROXY_MESSAGE_CONST_TTL)) + .addBody(SendMessageRequestBody.BIZSEQNO, message.getBizSeqNo()) + .addBody(SendMessageRequestBody.UNIQUEID, message.getUniqueId()); + + long startTime = System.currentTimeMillis(); + String targetRegion = + MapUtils.getObject(message.getProp(), Constants.TARGET_PROXY_REGION, Constants.CONSTANTS_DEFAULT_REGION_KEY); + String target = getCurrProxy(targetRegion); + String res = ""; + try { + res = HttpUtil.post(httpClient, target, requestParam); +// res = HttpUtil.post(httpClient, getAvailablesForwardAgent(), target, requestParam); + } catch (Exception ex) { + throw new ProxyException(ex); + } + + if(logger.isDebugEnabled()) { + logger.debug("publish async message, targetProxy:{}, cost:{}ms, message:{}, rtn:{}", + target, System.currentTimeMillis() - startTime, message, res); + } + + ProxyRetObj ret = JSON.parseObject(res, ProxyRetObj.class); + + if (ret.getRetCode() == ProxyRetCode.SUCCESS.getRetCode()) { + return Boolean.TRUE; + } else { + throw new ProxyException(ret.getRetCode(), ret.getRetMsg()); + } + } + + public String getCurrProxy(String targetRegion) { + List availableServers = getAvailableServers(targetRegion); + if (CollectionUtils.isEmpty(availableServers)) { + return null; + } + return Constants.HTTP_PROTOCOL_PREFIX + availableServers.get(RandomUtils.nextInt(0, availableServers.size())); + } + + public LiteMessage request(LiteMessage message, long timeout) throws ProxyException { + if(!started.get()) { + start(); + } + Preconditions.checkState(StringUtils.isNotBlank(message.getTopic()), + "proxyMessage[topic] invalid"); + Preconditions.checkState(StringUtils.isNotBlank(message.getContent()), + "proxyMessage[content] invalid"); + RequestParam requestParam = new RequestParam(HttpMethod.POST); + requestParam.addHeader(ProtocolKey.REQUEST_CODE, String.valueOf(RequestCode.MSG_SEND_SYNC.getRequestCode())) + .addHeader(ProtocolKey.ClientInstanceKey.ENV, liteClientConfig.getEnv()) + .addHeader(ProtocolKey.ClientInstanceKey.IDC, liteClientConfig.getIdc()) + .addHeader(ProtocolKey.ClientInstanceKey.IP, liteClientConfig.getIp()) + .addHeader(ProtocolKey.ClientInstanceKey.PID, liteClientConfig.getPid()) + .addHeader(ProtocolKey.ClientInstanceKey.SYS, liteClientConfig.getSys()) + .addHeader(ProtocolKey.ClientInstanceKey.USERNAME, liteClientConfig.getUserName()) + .addHeader(ProtocolKey.ClientInstanceKey.PASSWD, liteClientConfig.getPassword()) + .addHeader(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()) + .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) + .setTimeout(timeout) + .addBody(SendMessageRequestBody.PRODUCERGROUP, liteClientConfig.getProducerGroup()) + .addBody(SendMessageRequestBody.TOPIC, message.getTopic()) + .addBody(SendMessageRequestBody.CONTENT, message.getContent()) + .addBody(SendMessageRequestBody.TTL, String.valueOf(timeout)) + .addBody(SendMessageRequestBody.BIZSEQNO, message.getBizSeqNo()) + .addBody(SendMessageRequestBody.UNIQUEID, message.getUniqueId()); + + long startTime = System.currentTimeMillis(); + String targetRegion = + MapUtils.getObject(message.getProp(), Constants.TARGET_PROXY_REGION, Constants.CONSTANTS_DEFAULT_REGION_KEY); + String target = getCurrProxy(targetRegion); + String res = ""; + try { + //res = HttpUtil.post(httpClient, getAvailablesForwardAgent(), target, requestParam); + res = HttpUtil.post(httpClient, target, requestParam); + } catch (Exception ex) { + throw new ProxyException(ex); + } + + if(logger.isDebugEnabled()) { + logger.debug("publish sync message by await, targetProxy:{}, cost:{}ms, message:{}, rtn:{}", target, System.currentTimeMillis() - startTime, message, res); + } + + ProxyRetObj ret = JSON.parseObject(res, ProxyRetObj.class); + if (ret.getRetCode() == ProxyRetCode.SUCCESS.getRetCode()) { + LiteMessage proxyMessage = new LiteMessage(); + SendMessageResponseBody.ReplyMessage replyMessage = + JSON.parseObject(ret.getRetMsg(), SendMessageResponseBody.ReplyMessage.class); + proxyMessage.setContent(replyMessage.body).setProp(replyMessage.properties) + .setTopic(replyMessage.topic); + return proxyMessage; + } + + return null; + } + + public void request(LiteMessage message, RRCallback rrCallback, long timeout) throws ProxyException { + if(!started.get()) { + start(); + } + Preconditions.checkState(StringUtils.isNotBlank(message.getTopic()), + "proxyMessage[topic] invalid"); + Preconditions.checkState(StringUtils.isNotBlank(message.getContent()), + "proxyMessage[content] invalid"); + Preconditions.checkState(ObjectUtils.allNotNull(rrCallback), + "rrCallback invalid"); + RequestParam requestParam = new RequestParam(HttpMethod.POST); + requestParam.addHeader(ProtocolKey.REQUEST_CODE, String.valueOf(RequestCode.MSG_SEND_SYNC.getRequestCode())) + .addHeader(ProtocolKey.ClientInstanceKey.ENV, liteClientConfig.getEnv()) + .addHeader(ProtocolKey.ClientInstanceKey.IDC, liteClientConfig.getIdc()) + .addHeader(ProtocolKey.ClientInstanceKey.IP, liteClientConfig.getIp()) + .addHeader(ProtocolKey.ClientInstanceKey.PID, liteClientConfig.getPid()) + .addHeader(ProtocolKey.ClientInstanceKey.SYS, liteClientConfig.getSys()) + .addHeader(ProtocolKey.ClientInstanceKey.USERNAME, liteClientConfig.getUserName()) + .addHeader(ProtocolKey.ClientInstanceKey.PASSWD, liteClientConfig.getPassword()) + .addHeader(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()) + .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) + .setTimeout(timeout) + .addBody(SendMessageRequestBody.PRODUCERGROUP, liteClientConfig.getProducerGroup()) + .addBody(SendMessageRequestBody.TOPIC, message.getTopic()) + .addBody(SendMessageRequestBody.CONTENT, message.getContent()) + .addBody(SendMessageRequestBody.TTL, String.valueOf(timeout)) + .addBody(SendMessageRequestBody.BIZSEQNO, message.getBizSeqNo()) + .addBody(SendMessageRequestBody.UNIQUEID, message.getUniqueId()); + + long startTime = System.currentTimeMillis(); + String targetRegion = + MapUtils.getObject(message.getProp(), Constants.TARGET_PROXY_REGION, Constants.CONSTANTS_DEFAULT_REGION_KEY); + String target = getCurrProxy(targetRegion); + try { +// HttpUtil.post(httpClient, getAvailablesForwardAgent(), target, requestParam, new RRCallbackResponseHandlerAdapter(message, rrCallback, timeout)); + HttpUtil.post(httpClient, null, target, requestParam, new RRCallbackResponseHandlerAdapter(message, rrCallback, timeout)); + } catch (Exception ex) { + throw new ProxyException(ex); + } + + if(logger.isDebugEnabled()) { + logger.debug("publish sync message by async, target:{}, cost:{}, message:{}", target, System.currentTimeMillis() - startTime, message); + } + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/RRCallback.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/RRCallback.java new file mode 100644 index 0000000000..2ed60a5077 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/RRCallback.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/RRCallback.java +package cn.webank.eventmesh.client.http.producer; +======== +package org.apache.eventmesh.client.http.producer; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallback.java + + +import cn.webank.eventmesh.common.LiteMessage; + +public interface RRCallback { + + void onSuccess(LiteMessage liteMessage); + + void onException(Throwable e); + +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java new file mode 100644 index 0000000000..1d89c7adc4 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java +package cn.webank.eventmesh.client.http.producer; + +import cn.webank.eventmesh.client.http.ProxyRetObj; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.LiteMessage; +import cn.webank.eventmesh.common.ProxyException; +import cn.webank.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import cn.webank.eventmesh.common.protocol.http.common.ProxyRetCode; +======== +package org.apache.eventmesh.client.http.producer; + +import org.apache.eventmesh.client.http.EventMeshRetObj; +import com.webank.eventmesh.common.Constants; +import com.webank.eventmesh.common.LiteMessage; +import com.webank.eventmesh.common.EventMeshException; +import com.webank.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import com.webank.eventmesh.common.protocol.http.common.EventMeshRetCode; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java +import com.alibaba.fastjson.JSON; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.ResponseHandler; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.charset.Charset; + +public class RRCallbackResponseHandlerAdapter implements ResponseHandler { + + public Logger logger = LoggerFactory.getLogger(RRCallbackResponseHandlerAdapter.class); + + private long createTime; + + private LiteMessage liteMessage; + + private RRCallback rrCallback; + + private long timeout; + + public RRCallbackResponseHandlerAdapter(LiteMessage liteMessage, RRCallback rrCallback, long timeout) { + this.liteMessage = liteMessage; + this.rrCallback = rrCallback; + this.timeout = timeout; + this.createTime = System.currentTimeMillis(); + } + + @Override + public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException { + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + rrCallback.onException(new ProxyException(response.toString())); + return response.toString(); + } + + if (System.currentTimeMillis() - createTime > timeout) { + String err = String.format("response too late, bizSeqNo=%s, uniqueId=%s, createTime=%s, ttl=%s, cost=%sms", + liteMessage.getBizSeqNo(), + liteMessage.getUniqueId(), + DateFormatUtils.format(createTime, Constants.DATE_FORMAT), + timeout, + System.currentTimeMillis() - createTime); + logger.warn(err); + rrCallback.onException(new ProxyException(err)); + return err; + } + + String res = EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET)); + ProxyRetObj ret = JSON.parseObject(res, ProxyRetObj.class); + if (ret.getRetCode() != ProxyRetCode.SUCCESS.getRetCode()) { + rrCallback.onException(new ProxyException(ret.getRetCode(), ret.getRetMsg())); + return res; + } + + LiteMessage liteMessage = new LiteMessage(); + try { + SendMessageResponseBody.ReplyMessage replyMessage = + JSON.parseObject(ret.getRetMsg(), SendMessageResponseBody.ReplyMessage.class); + liteMessage.setContent(replyMessage.body).setProp(replyMessage.properties) + .setTopic(replyMessage.topic); + rrCallback.onSuccess(liteMessage); + } catch (Exception ex) { + rrCallback.onException(new ProxyException(ex)); + return ex.toString(); + } + + return liteMessage.toString(); + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/SimplePubClient.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/SimplePubClient.java new file mode 100644 index 0000000000..08aa882a4f --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/SimplePubClient.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/SimplePubClient.java +package cn.webank.eventmesh.client.tcp; + + +import cn.webank.eventmesh.client.tcp.common.AsyncRRCallback; +import cn.webank.eventmesh.client.tcp.common.ReceiveMsgHook; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import cn.webank.eventmesh.common.protocol.tcp.Package; +======== +package org.apache.eventmesh.client.tcp; + + +import org.apache.eventmesh.client.tcp.common.AsyncRRCallback; +import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +import com.webank.eventmesh.common.protocol.tcp.Package; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/SimplePubClient.java + +/** + * + * Created by nanoxiong on 2017/4/26. + */ +public interface SimplePubClient { + + void init() throws Exception; + + void close(); + + void heartbeat() throws Exception; + + void reconnect() throws Exception; + + Package rr(Package msg, long timeout) throws Exception; + + void asyncRR(Package msg, AsyncRRCallback callback, long timeout) throws Exception; + + Package publish(Package msg, long timeout) throws Exception; + + void broadcast(Package msg, long timeout) throws Exception; + + void registerBusiHandler(ReceiveMsgHook handler) throws Exception; + + UserAgent getUserAgent(); +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/SimpleSubClient.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/SimpleSubClient.java new file mode 100644 index 0000000000..23e151e626 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/SimpleSubClient.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/SimpleSubClient.java +package cn.webank.eventmesh.client.tcp; + + +import cn.webank.eventmesh.client.tcp.common.ReceiveMsgHook; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +======== +package org.apache.eventmesh.client.tcp; + + +import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/SimpleSubClient.java + +/** + * Created by nanoxiong on 2017/4/26. + */ +public interface SimpleSubClient { + void init() throws Exception; + + void close(); + + void heartbeat() throws Exception; + + void reconnect() throws Exception; + + void subscribe(String topic) throws Exception; + + void unsubscribe() throws Exception; + + void listen() throws Exception; + + void registerBusiHandler(ReceiveMsgHook handler) throws Exception; + + UserAgent getUserAgent(); +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/WemqAccessClient.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/WemqAccessClient.java new file mode 100644 index 0000000000..737ba23f3e --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/WemqAccessClient.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/WemqAccessClient.java +package cn.webank.eventmesh.client.tcp; + +import cn.webank.eventmesh.client.tcp.common.AsyncRRCallback; +import cn.webank.eventmesh.client.tcp.common.ReceiveMsgHook; +import cn.webank.eventmesh.common.protocol.tcp.Package; +======== +package org.apache.eventmesh.client.tcp; + +import org.apache.eventmesh.client.tcp.common.AsyncRRCallback; +import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; +import com.webank.eventmesh.common.protocol.tcp.Package; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshClient.java + +public interface EventMeshClient { + + Package rr(Package msg, long timeout) throws Exception; + + void asyncRR(Package msg, AsyncRRCallback callback, long timeout) throws Exception; + + Package publish(Package msg, long timeout) throws Exception; + + void broadcast(Package msg, long timeout) throws Exception; + + void init() throws Exception; + + void close(); + + void heartbeat() throws Exception; + + void listen() throws Exception; + + void subscribe(String topic) throws Exception; + + void unsubscribe() throws Exception; + + void registerPubBusiHandler(ReceiveMsgHook handler) throws Exception; + + void registerSubBusiHandler(ReceiveMsgHook handler) throws Exception; + + SimplePubClient getPubClient(); + + SimpleSubClient getSubClient(); +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/AsyncRRCallback.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/AsyncRRCallback.java new file mode 100644 index 0000000000..f70b4dd33a --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/AsyncRRCallback.java @@ -0,0 +1,27 @@ +/* + * 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 cn.webank.eventmesh.client.tcp.common; +import cn.webank.eventmesh.common.protocol.tcp.Package; + +/** + * Created by nanoxiong on 2017/5/30. + * 异步RR回调 ,只针对RR + */ +public interface AsyncRRCallback { + void callback(Package msg); +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/MessageUtils.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/MessageUtils.java new file mode 100644 index 0000000000..d445f49608 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/MessageUtils.java @@ -0,0 +1,154 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/MessageUtils.java +package cn.webank.eventmesh.client.tcp.common; +======== +package org.apache.eventmesh.client.tcp.common; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/MessageUtils.java + +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.Subscription; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +/** + * MessageUtil + * + */ +public class MessageUtils { + private static final int seqLength = 10; + + public static Package hello(UserAgent user) { + Package msg = new Package(); + msg.setHeader(new Header(Command.HELLO_REQUEST, 0, null, generateRandomString(seqLength))); + msg.setBody(user); + return msg; + } + + public static Package heartBeat() { + Package msg = new Package(); + msg.setHeader(new Header(Command.HEARTBEAT_REQUEST, 0, null, generateRandomString(seqLength))); + return msg; + } + + public static Package goodbye() { + Package msg = new Package(); + msg.setHeader(new Header(Command.CLIENT_GOODBYE_REQUEST, 0, null, generateRandomString(seqLength))); + return msg; + } + + public static Package listen() { + Package msg = new Package(); + msg.setHeader(new Header(Command.LISTEN_REQUEST, 0, null, generateRandomString(seqLength))); + return msg; + } + + public static Package subscribe(String topic) { + Package msg = new Package(); + msg.setHeader(new Header(Command.SUBSCRIBE_REQUEST, 0, null, generateRandomString(seqLength))); + msg.setBody(generateSubscription(topic)); + return msg; + } + + public static Package unsubscribe() { + Package msg = new Package(); + msg.setHeader(new Header(Command.UNSUBSCRIBE_REQUEST, 0, null, generateRandomString(seqLength))); + return msg; + } + + public static Package asyncMessageAck(Package in) { + Package msg = new Package(); + msg.setHeader(new Header(Command.ASYNC_MESSAGE_TO_CLIENT_ACK, 0, null, in.getHeader().getSeq())); + msg.setBody(in.getBody()); + return msg; + } + + public static Package broadcastMessageAck(Package in) { + Package msg = new Package(); + msg.setHeader(new Header(Command.BROADCAST_MESSAGE_TO_CLIENT_ACK, 0, null, in.getHeader().getSeq())); + msg.setBody(in.getBody()); + return msg; + } + + public static Package requestToClientAck(Package in) { + Package msg = new Package(); + msg.setHeader(new Header(Command.REQUEST_TO_CLIENT_ACK, 0, null, in.getHeader().getSeq())); + msg.setBody(in.getBody()); + return msg; + } + + public static Package responseToClientAck(Package in) { + Package msg = new Package(); + msg.setHeader(new Header(Command.RESPONSE_TO_CLIENT_ACK, 0, null, in.getHeader().getSeq())); + msg.setBody(in.getBody()); + return msg; + } + + public static UserAgent generateSubClient(UserAgent agent) { + UserAgent user = new UserAgent(); + user.setHost(agent.getHost()); + user.setPassword(agent.getPassword()); + user.setUsername(agent.getUsername()); + user.setPath(agent.getPath()); + user.setPort(agent.getPort()); + user.setSubsystem(agent.getSubsystem()); + user.setPid(agent.getPid()); + user.setVersion(agent.getVersion()); + user.setIdc(agent.getIdc()); + + user.setPurpose(EventMeshCommon.USER_AGENT_PURPOSE_SUB); + return user; + } + + public static UserAgent generatePubClient(UserAgent agent) { + UserAgent user = new UserAgent(); + user.setHost(agent.getHost()); + user.setPassword(agent.getPassword()); + user.setUsername(agent.getUsername()); + user.setPath(agent.getPath()); + user.setPort(agent.getPort()); + user.setSubsystem(agent.getSubsystem()); + user.setPid(agent.getPid()); + user.setVersion(agent.getVersion()); + user.setIdc(agent.getIdc()); + + user.setPurpose(EventMeshCommon.USER_AGENT_PURPOSE_PUB); + return user; + } + + private static Subscription generateSubscription(String topic) { + Subscription subscription = new Subscription(); + List topicList = new ArrayList<>(); + topicList.add(topic); + subscription.setTopicList(topicList); + return subscription; + } + + private static String generateRandomString(int length) { + StringBuilder builder = new StringBuilder(length); + for (int i = 0; i < length; i++) { + builder.append((char) ThreadLocalRandom.current().nextInt(48, 57)); + } + return builder.toString(); + } +} + diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/ReceiveMsgHook.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/ReceiveMsgHook.java new file mode 100644 index 0000000000..1773936113 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/ReceiveMsgHook.java @@ -0,0 +1,28 @@ +/* + * 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 cn.webank.eventmesh.client.tcp.common; + +import io.netty.channel.ChannelHandlerContext; +import cn.webank.eventmesh.common.protocol.tcp.Package; +/** + * Created by nanoxiong on 2017/4/26. + * 业务回调钩子, 这是针对所有类型的消息都会进行的回调 + */ +public interface ReceiveMsgHook { + void handle(Package msg, ChannelHandlerContext ctx); +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/RequestContext.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/RequestContext.java new file mode 100644 index 0000000000..a0add5c536 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/RequestContext.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/RequestContext.java +package cn.webank.eventmesh.client.tcp.common; +======== +package org.apache.eventmesh.client.tcp.common; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/RequestContext.java + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import java.util.concurrent.CountDownLatch; + +/** + * Created by nanoxiong on 2017/4/26. + */ +public class RequestContext { + + private static Logger logger = LoggerFactory.getLogger(RequestContext.class); + + private Object key; + private Package request; + private Package response; + private CountDownLatch latch; + + public RequestContext(Object key, Package request, CountDownLatch latch) { + this.key = key; + this.request = request; + this.latch = latch; + } + + public Object getKey() { + return key; + } + + public void setKey(Object key) { + this.key = key; + } + + public Package getRequest() { + return request; + } + + public void setRequest(Package request) { + this.request = request; + } + + public Package getResponse() { + return response; + } + + public void setResponse(Package response) { + this.response = response; + } + + public CountDownLatch getLatch() { + return latch; + } + + public void setLatch(CountDownLatch latch) { + this.latch = latch; + } + + public void finish(Package msg) { + this.response = msg; + latch.countDown(); + } + + public static RequestContext _context(Object key, Package request, CountDownLatch latch) throws Exception { + RequestContext c = new RequestContext(key, request, latch); + logger.info("_RequestContext|create|key=" + key); + return c; + } + + + public static Object _key(Package request) { +// MessageType type = request.getHeader().getType(); +// if(MessageType.SyncRequest == type || MessageType.SyncResponse == type +// || MessageType.AsyncRequest == type || MessageType.AsyncResponse == type) { +// return request.getBody().getSysHeader().getUniqueId() ; +// } + return request.getHeader().getSeq(); + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/TcpClient.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/TcpClient.java new file mode 100644 index 0000000000..aa797287ad --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/TcpClient.java @@ -0,0 +1,142 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/TcpClient.java +package cn.webank.eventmesh.client.tcp.common; +======== +package org.apache.eventmesh.client.tcp.common; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/TcpClient.java + +import cn.webank.eventmesh.common.protocol.tcp.codec.Codec; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import java.io.Closeable; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.Random; +import java.util.concurrent.*; + +public abstract class TcpClient implements Closeable { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + public int clientNo = (new Random()).nextInt(1000); + + protected ConcurrentHashMap contexts = new ConcurrentHashMap<>(); + + private final String host; + private final int port; + + private Bootstrap bootstrap = new Bootstrap(); + + private EventLoopGroup workers = new NioEventLoopGroup(); + + private Channel channel; + + protected static final ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(4, new EventMeshThreadFactoryImpl("TCPClientScheduler", true)); + + private ScheduledFuture task; + + public TcpClient(String host, int port){ + this.host = host; + this.port = port; + } + + protected synchronized void open(SimpleChannelInboundHandler handler) throws Exception { + bootstrap.group(workers); + bootstrap.channel(NioSocketChannel.class); + bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1_000) + .option(ChannelOption.SO_KEEPALIVE, true) + .option(ChannelOption.SO_SNDBUF, 64 * 1024) + .option(ChannelOption.SO_RCVBUF, 64 * 1024) + .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(1024, 8192, 65536)) + .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); + bootstrap.handler(new ChannelInitializer() { + public void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast(new Codec.Encoder(), new Codec.Decoder()) + .addLast(handler, newExceptionHandler()); + } + }); + + ChannelFuture f = bootstrap.connect(host, port).sync(); + InetSocketAddress localAddress = (InetSocketAddress) f.channel().localAddress(); + channel = f.channel(); + logger.info("connected|local={}:{}|server={}", localAddress.getAddress().getHostAddress(), localAddress.getPort(), host + ":" + port); + } + + @Override + public void close() throws IOException { + try { + channel.disconnect().sync(); + } catch (InterruptedException e) { + logger.warn("close tcp client failed.|remote address={}", channel.remoteAddress(), e); + } + workers.shutdownGracefully(); + } + + protected synchronized void reconnect() throws Exception { + ChannelFuture f = bootstrap.connect(host, port).sync(); + channel = f.channel(); + } + + protected boolean isActive() { + return (channel != null) && (channel.isActive()); + } + + protected void send(Package msg) throws Exception { + if (channel.isWritable()) { + channel.writeAndFlush(msg).addListener((ChannelFutureListener) future -> { + if (!future.isSuccess()) { + logger.warn("send msg failed", future.isSuccess(), future.cause()); + } + }); + } else { + channel.writeAndFlush(msg).sync(); + } + } + + protected Package io(Package msg, long timeout) throws Exception { + Object key = RequestContext._key(msg); + CountDownLatch latch = new CountDownLatch(1); + RequestContext c = RequestContext._context(key, msg, latch); + if (!contexts.contains(c)) { + contexts.put(key, c); + } else { + logger.info("duplicate key : {}", key); + } + send(msg); + if (!c.getLatch().await(timeout, TimeUnit.MILLISECONDS)) + throw new TimeoutException("operation timeout, context.key=" + c.getKey()); + return c.getResponse(); + } + + private ChannelDuplexHandler newExceptionHandler() { + return new ChannelDuplexHandler() { + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + logger.info("exceptionCaught, close connection.|remote address={}",ctx.channel().remoteAddress(),cause); + ctx.close(); + } + }; + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/WemqAccessCommon.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/WemqAccessCommon.java new file mode 100644 index 0000000000..fc35c47325 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/WemqAccessCommon.java @@ -0,0 +1,133 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/WemqAccessCommon.java +package cn.webank.eventmesh.client.tcp.common; +======== +package org.apache.eventmesh.client.tcp.common; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/EventMeshCommon.java + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/WemqAccessCommon.java +/** + * Created by nanoxiong on 2017/6/8. + */ +public class WemqAccessCommon { +======== +public class EventMeshCommon { +>>>>>>>> 4ed546fd7 ([ISSUE #265]rename wemq and access to eventmesh):eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/EventMeshCommon.java + /** + * 打印线程池状态的间隔时间 + */ + public static int PRINTTHREADPOOLSTATE_INTEVAL = 1; + + /** + * 数据上报给logServer间隔时间 + */ + public static int LOGSERVER_INTEVAL = 1 * 60 * 1000; + + /** + * CLIENT端心跳间隔时间 + */ + public static int HEATBEAT = 30 * 1000; + + /** + * RR 废弃清理的时间间隔 + */ + public static int REQUEST_CONTEXT_CLEAN_EXPIRE = 60 * 1000; + + /** + * METRICS 废弃清理的时间间隔 + */ + public static int METRICS_CLEAN_EXPIRE = 2 * 1000; + + /** + * SESSION 废弃清理的时间间隔 + */ + public static int SESSION_CLEAN_EXPIRE = 5 * 1000; + + /** + * EventMesh校验用户名 + */ + public static String EventMesh_USER = "EventMesh"; + + /** + * EventMesh校验用户密码 + */ + public static String EventMesh_PASS = "EventMesh@123"; + + /** + * 服务器共有的超时时间 + */ + public static int DEFAULT_TIME_OUT_MILLS = 5 * 1000; + + /** + * PUB用途的USERAGENT + */ + public static String USER_AGENT_PURPOSE_PUB = "pub"; + + /** + * SUB用途的USERAGENT + */ + public static String USER_AGENT_PURPOSE_SUB = "sub"; + + /** + * 集群消费者消费组前缀 + */ + public static String PREFIX_CONSUMER_GROUP_CLUSTERING = "clustering"; + + /** + * 广播消费者消费组前缀 + */ + public static String PREFIX_CONSUMER_GROUP_BROADCASTING = "broadcast"; + + /** + * RR 的请求消息存储的集群具体IP地址和端口 + */ + public static String KEY_RR_REQ_STROE_ADDRESS = "rr_req_store_addr"; + + /** + * RR请求消息存储在WEMQ上的MSGID + */ + public static String KEY_RR_REQ_WEMQ_MSG_ID = "rr_req_wemq_msg_id"; + + /** + * 如果多个TOPIC都是旁路消息,下发给C时 都按这个 TOPIC 给,C匹配到这个 bq-bypass 则认为是旁路,则按旁路解析 + */ + public static String KEY_BYPASS_MSG_ORIGINAL_TOPIC = "original_topic"; + + /** + * Client端查询服务器的server级别的统计数据的标识KEY + */ + public static String KEY_QUERY_SERVER_STATISTICS = "server-statistic"; + + /** + * Client端查询服务器的session级别的统计数据的标识KEY + */ + public static String KEY_QUERY_SESSION_STATISTICS = "session-statistic"; + + /** + * SESSION 统计TPS 前缀区分 + */ + public static String PREFIX_SESSION_TPS_STAT_RRSEND = "rr_send_tps_"; + + public static String PREFIX_SESSION_TPS_STAT_RRREV = "rr_rev_tps_"; + + public static String PREFIX_SESSION_TPS_STAT_EVENTSEND = "event_send_tps_"; + + public static String PREFIX_SESSION_TPS_STAT_EVENTREV = "event_rev_tps_"; + +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/WemqAccessThreadFactoryImpl.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/WemqAccessThreadFactoryImpl.java new file mode 100644 index 0000000000..3c9c589f1d --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/WemqAccessThreadFactoryImpl.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/common/WemqAccessThreadFactoryImpl.java +package cn.webank.eventmesh.client.tcp.common; +======== +package org.apache.eventmesh.client.tcp.common; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/EventMeshThreadFactoryImpl.java + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicLong; + +public class EventMeshThreadFactoryImpl implements ThreadFactory { + private final AtomicLong threadIndex = new AtomicLong(0); + private final String threadNamePrefix; + private Boolean isDaemonSpecified = null; + + public EventMeshThreadFactoryImpl(final String threadNamePrefix) { + this.threadNamePrefix = threadNamePrefix; + } + + public EventMeshThreadFactoryImpl(final String threadNamePrefix, final boolean isDaemonSpecified) { + this.threadNamePrefix = threadNamePrefix; + this.isDaemonSpecified = isDaemonSpecified; + } + + public String getThreadNamePrefix() { + return threadNamePrefix; + } + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, threadNamePrefix +'-'+ this.threadIndex.incrementAndGet()); + if (isDaemonSpecified != null) { + t.setDaemon(isDaemonSpecified); + } + return t; + } +} \ No newline at end of file diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/DefaultWemqAccessClient.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/DefaultWemqAccessClient.java new file mode 100644 index 0000000000..e87beb71b2 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/DefaultWemqAccessClient.java @@ -0,0 +1,157 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/DefaultWemqAccessClient.java +package cn.webank.eventmesh.client.tcp.impl; + + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/DefaultWemqAccessClient.java +import cn.webank.eventmesh.client.tcp.SimplePubClient; +import cn.webank.eventmesh.client.tcp.SimpleSubClient; +import cn.webank.eventmesh.client.tcp.WemqAccessClient; +import cn.webank.eventmesh.client.tcp.common.AsyncRRCallback; +import cn.webank.eventmesh.client.tcp.common.MessageUtils; +import cn.webank.eventmesh.client.tcp.common.ReceiveMsgHook; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import cn.webank.eventmesh.common.protocol.tcp.Package; + +/** + * Created by nanoxiong on 2017/5/24. + * C 客户端的模拟器 + */ +public class DefaultWemqAccessClient implements WemqAccessClient { +======== +import com.webank.eventmesh.client.tcp.SimplePubClient; +import com.webank.eventmesh.client.tcp.SimpleSubClient; +import com.webank.eventmesh.client.tcp.EventMeshClient; +import com.webank.eventmesh.client.tcp.common.AsyncRRCallback; +import com.webank.eventmesh.client.tcp.common.MessageUtils; +import com.webank.eventmesh.client.tcp.common.ReceiveMsgHook; +======== +package org.apache.eventmesh.client.tcp.impl; + + +import org.apache.eventmesh.client.tcp.SimplePubClient; +import org.apache.eventmesh.client.tcp.SimpleSubClient; +import org.apache.eventmesh.client.tcp.EventMeshClient; +import org.apache.eventmesh.client.tcp.common.AsyncRRCallback; +import org.apache.eventmesh.client.tcp.common.MessageUtils; +import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/DefaultEventMeshClient.java +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +import com.webank.eventmesh.common.protocol.tcp.Package; + +public class DefaultEventMeshClient implements EventMeshClient { +>>>>>>>> 4ed546fd7 ([ISSUE #265]rename wemq and access to eventmesh):eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/DefaultEventMeshClient.java + protected UserAgent agent; + private String accessHost; + private int accessPort; + + private SimplePubClient pubClient; + private SimpleSubClient subClient; + + public DefaultEventMeshClient(String accessHost, int accessPort, UserAgent agent) { + this.accessHost = accessHost; + this.accessPort = accessPort; + this.agent = agent; + + UserAgent subAgent = MessageUtils.generateSubClient(agent); + this.subClient = new SimpleSubClientImpl(accessHost, accessPort, subAgent); + + UserAgent pubAgent = MessageUtils.generatePubClient(agent); + this.pubClient = new SimplePubClientImpl(accessHost, accessPort, pubAgent); + } + + public SimplePubClient getPubClient() { + return pubClient; + } + + public void setPubClient(SimplePubClient pubClient) { + this.pubClient = pubClient; + } + + public SimpleSubClient getSubClient() { + return subClient; + } + + public void setSubClient(SimpleSubClient subClient) { + this.subClient = subClient; + } + + public Package rr(Package msg, long timeout) throws Exception { + return this.pubClient.rr(msg, timeout); + } + + public Package publish(Package msg, long timeout) throws Exception { + return this.pubClient.publish(msg, timeout); + } + + public void broadcast(Package msg, long timeout) throws Exception { + this.pubClient.broadcast(msg, timeout); + } + + public void init() throws Exception { + this.subClient.init(); + this.pubClient.init(); + } + + public void close() { + this.pubClient.close(); + this.subClient.close(); + } + + public void heartbeat() throws Exception { + this.pubClient.heartbeat(); + this.subClient.heartbeat(); + } + + public void listen() throws Exception { + this.subClient.listen(); + } + + @Override + public void subscribe(String topic) throws Exception { + this.subClient.subscribe(topic); + } + + @Override + public void unsubscribe() throws Exception { + this.subClient.unsubscribe(); + } + + public void registerSubBusiHandler(ReceiveMsgHook handler) throws Exception { + this.subClient.registerBusiHandler(handler); + } + + @Override + public void asyncRR(Package msg, AsyncRRCallback callback, long timeout) throws Exception { + this.pubClient.asyncRR(msg, callback, timeout); + } + + public void registerPubBusiHandler(ReceiveMsgHook handler) throws Exception { + this.pubClient.registerBusiHandler(handler); + } + + @Override + public String toString() { + return "DefaultEventMeshClient{" + + "accessHost='" + accessHost + '\'' + + ", accessPort=" + accessPort + + ", agent=" + agent + + '}'; + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/SimplePubClientImpl.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/SimplePubClientImpl.java new file mode 100644 index 0000000000..c0d1bd9cad --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/SimplePubClientImpl.java @@ -0,0 +1,212 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/SimplePubClientImpl.java +package cn.webank.eventmesh.client.tcp.impl; + +import cn.webank.eventmesh.client.tcp.SimplePubClient; +import cn.webank.eventmesh.client.tcp.common.AsyncRRCallback; +import cn.webank.eventmesh.client.tcp.common.MessageUtils; +import cn.webank.eventmesh.client.tcp.common.ReceiveMsgHook; +import cn.webank.eventmesh.client.tcp.common.RequestContext; +import cn.webank.eventmesh.client.tcp.common.TcpClient; +import cn.webank.eventmesh.client.tcp.common.WemqAccessCommon; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +======== +package org.apache.eventmesh.client.tcp.impl; + +import org.apache.eventmesh.client.tcp.SimplePubClient; +import org.apache.eventmesh.client.tcp.common.AsyncRRCallback; +import org.apache.eventmesh.client.tcp.common.MessageUtils; +import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; +import org.apache.eventmesh.client.tcp.common.RequestContext; +import org.apache.eventmesh.client.tcp.common.TcpClient; +import org.apache.eventmesh.client.tcp.common.EventMeshCommon; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/SimplePubClientImpl.java +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import cn.webank.eventmesh.common.protocol.tcp.Package; + +/** + * Created by nanoxiong on 2017/4/25. + */ +public class SimplePubClientImpl extends TcpClient implements SimplePubClient { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + private UserAgent userAgent; + + private ReceiveMsgHook callback; + + private ConcurrentHashMap callbackConcurrentHashMap = new ConcurrentHashMap(); + private ScheduledFuture task; + + public SimplePubClientImpl(String accessIp, int port, UserAgent agent) { + super(accessIp, port); + this.userAgent = agent; + } + + public void registerBusiHandler(ReceiveMsgHook handler) throws Exception { + callback = handler; + } + + public void init() throws Exception { + open(new Handler()); + hello(); + logger.info("SimplePubClientImpl|{}|started!", clientNo); + } + + public void reconnect() throws Exception { + super.reconnect(); + hello(); + } + + public void close() { + try { + task.cancel(false); + goodbye(); + super.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void heartbeat() throws Exception { + task = scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + try { + if (!isActive()) { + SimplePubClientImpl.this.reconnect(); + } + Package msg = MessageUtils.heartBeat(); + io(msg, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + } catch (Exception e) { + } + } + }, WemqAccessCommon.HEATBEAT, WemqAccessCommon.HEATBEAT, TimeUnit.MILLISECONDS); + } + + private void goodbye() throws Exception { + Package msg = MessageUtils.goodbye(); + this.io(msg, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + } + + private void hello() throws Exception { + Package msg = MessageUtils.hello(userAgent); + this.io(msg, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + } + + /** + * 发送RR消息 + * + * @param msg + * @param timeout + * @return + * @throws Exception + */ + public Package rr(Package msg, long timeout) throws Exception { + logger.info("SimplePubClientImpl|{}|rr|send|type={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); + return io(msg, timeout); + } + + /** + * 异步RR + * + * @param msg + * @param callback + * @param timeout + * @throws Exception + */ + @Override + public void asyncRR(Package msg, AsyncRRCallback callback, long timeout) throws Exception { + super.send(msg); + this.callbackConcurrentHashMap.put((String) RequestContext._key(msg), callback); + + } + + /** + * 发送事件消息, 只所以有返回值是ACCESS 给了ACK + * + * @param msg + * @throws Exception + */ + public Package publish(Package msg, long timeout) throws Exception { + logger.info("SimplePubClientImpl|{}|publish|send|type={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); + return io(msg, timeout); + } + + /** + * 发送广播消息 + * + * @param msg + * @param timeout + * @throws Exception + */ + public void broadcast(Package msg, long timeout) throws Exception { + logger.info("SimplePubClientImpl|{}|broadcast|send|type={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); + super.send(msg); + } + + @Override + public UserAgent getUserAgent() { + return userAgent; + } + + @ChannelHandler.Sharable + private class Handler extends SimpleChannelInboundHandler { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Package msg) throws Exception { + logger.info("SimplePubClientImpl|{}|receive|type={}|msg={}", clientNo, msg.getHeader(), msg); + if (callback != null) { + callback.handle(msg, ctx); + } + + Command cmd = msg.getHeader().getCommand(); + if (cmd == Command.RESPONSE_TO_CLIENT) { + Package pkg = MessageUtils.responseToClientAck(msg); + send(pkg); + } else if (cmd == Command.SERVER_GOODBYE_REQUEST) { + + } + + RequestContext context = contexts.get(RequestContext._key(msg)); + if (context != null) { + contexts.remove(context.getKey()); + context.finish(msg); + return; + } else { + return; + } + } + } + + @Override + public String toString() { + return "SimplePubClientImpl|clientNo=" + clientNo + "|" + userAgent; + } +} diff --git a/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/SimpleSubClientImpl.java b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/SimpleSubClientImpl.java new file mode 100644 index 0000000000..ac9b0d4dd2 --- /dev/null +++ b/eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/SimpleSubClientImpl.java @@ -0,0 +1,193 @@ +/* + * 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. + */ + +<<<<<<<< HEAD:eventmesh-sdk-java/src/main/java/cn/webank/eventmesh/client/tcp/impl/SimpleSubClientImpl.java +package cn.webank.eventmesh.client.tcp.impl; + +import cn.webank.eventmesh.client.tcp.SimpleSubClient; +import cn.webank.eventmesh.client.tcp.common.MessageUtils; +import cn.webank.eventmesh.client.tcp.common.ReceiveMsgHook; +import cn.webank.eventmesh.client.tcp.common.RequestContext; +import cn.webank.eventmesh.client.tcp.common.TcpClient; +import cn.webank.eventmesh.client.tcp.common.WemqAccessCommon; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +======== +package org.apache.eventmesh.client.tcp.impl; + +import org.apache.eventmesh.client.tcp.SimpleSubClient; +import org.apache.eventmesh.client.tcp.common.MessageUtils; +import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; +import org.apache.eventmesh.client.tcp.common.RequestContext; +import org.apache.eventmesh.client.tcp.common.TcpClient; +import org.apache.eventmesh.client.tcp.common.EventMeshCommon; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/SimpleSubClientImpl.java +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import org.apache.commons.collections4.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import cn.webank.eventmesh.common.protocol.tcp.Package; + +/** + * Created by nanoxiong on 2017/4/26. + */ +public class SimpleSubClientImpl extends TcpClient implements SimpleSubClient { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + private UserAgent userAgent; + + private ReceiveMsgHook callback; + + private List topics = new ArrayList(); + + private ScheduledFuture task; + + public SimpleSubClientImpl(String accessIp, int port, UserAgent agent) { + super(accessIp, port); + this.userAgent = agent; + } + + public void registerBusiHandler(ReceiveMsgHook handler) throws Exception { + callback = handler; + } + + public void init() throws Exception { + open(new Handler()); + hello(); + logger.info("SimpleSubClientImpl|{}|started!", clientNo); + } + + public void reconnect() throws Exception { + super.reconnect(); + hello(); + if (!CollectionUtils.isEmpty(topics)) { + for (String topic : topics) { + Package request = MessageUtils.subscribe(topic); + this.io(request, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + } + } + listen(); + } + + public void close() { + try { + task.cancel(false); + goodbye(); + super.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void heartbeat() throws Exception { + task = scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + try { + if (!isActive()) { + SimpleSubClientImpl.this.reconnect(); + } + Package msg = MessageUtils.heartBeat(); + SimpleSubClientImpl.this.io(msg, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + } catch (Exception e) { + } + } + }, WemqAccessCommon.HEATBEAT, WemqAccessCommon.HEATBEAT, TimeUnit.MILLISECONDS); + } + + private void goodbye() throws Exception { + Package msg = MessageUtils.goodbye(); + this.io(msg, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + } + + private void hello() throws Exception { + Package msg = MessageUtils.hello(userAgent); + this.io(msg, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + } + + public void listen() throws Exception { + Package request = MessageUtils.listen(); + this.io(request, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + } + + + public void subscribe(String topic) throws Exception { + topics.add(topic); + Package request = MessageUtils.subscribe(topic); + this.io(request, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + } + + public void unsubscribe() throws Exception { + Package request = MessageUtils.unsubscribe(); + this.io(request, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + } + + public UserAgent getUserAgent() { + return userAgent; + } + + @ChannelHandler.Sharable + private class Handler extends SimpleChannelInboundHandler { + @SuppressWarnings("Duplicates") + @Override + protected void channelRead0(ChannelHandlerContext ctx, Package msg) throws Exception { + Command cmd = msg.getHeader().getCommand(); + logger.info(SimpleSubClientImpl.class.getSimpleName() + "|receive|type={}|msg={}", cmd, msg); + if (callback != null) { + callback.handle(msg, ctx); + } + if (cmd == Command.REQUEST_TO_CLIENT) { + Package pkg = MessageUtils.requestToClientAck(msg); + send(pkg); + } else if (cmd == Command.ASYNC_MESSAGE_TO_CLIENT) { + Package pkg = MessageUtils.asyncMessageAck(msg); + send(pkg); + } else if (cmd == Command.BROADCAST_MESSAGE_TO_CLIENT) { + Package pkg = MessageUtils.broadcastMessageAck(msg); + send(pkg); + } else if (cmd == Command.SERVER_GOODBYE_REQUEST) { + //TODO + } else { + logger.error("msg ignored|{}|{}", cmd, msg); + } + RequestContext context = contexts.get(RequestContext._key(msg)); + if (context != null) { + contexts.remove(context.getKey()); + context.finish(msg); + return; + } else { + logger.error("msg ignored,context not found.|{}|{}", cmd, msg); + return; + } + } + } + + @Override + public String toString() { + return "SimpleSubClientImpl|clientNo=" + clientNo + "|" + userAgent; + } +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/http/demo/AsyncPublishInstance.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/http/demo/AsyncPublishInstance.java new file mode 100644 index 0000000000..34d891c5bb --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/http/demo/AsyncPublishInstance.java @@ -0,0 +1,67 @@ +package cn.webank.eventmesh.client.http.demo; +import cn.webank.eventmesh.client.http.conf.LiteClientConfig; +import cn.webank.eventmesh.client.http.producer.LiteProducer; +import cn.webank.eventmesh.common.Constants; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.LiteMessage; +import cn.webank.eventmesh.common.ThreadUtil; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AsyncPublishInstance { + + public static Logger logger = LoggerFactory.getLogger(AsyncPublishInstance.class); + + public static void main(String[] args) throws Exception { + String confCenterAddr = args[0]; + String proxyIPPort = args[1]; + String topic = args[2]; + String packetSize = args[3]; + + if (StringUtils.isBlank(confCenterAddr)) { + confCenterAddr = "http://127.0.0.1:8090"; + } + + if (StringUtils.isBlank(topic)) { + topic = "topic-async-test"; + } + + if (StringUtils.isBlank(proxyIPPort)) { + proxyIPPort = "127.0.0.1:10105"; + } + + if (StringUtils.isBlank(packetSize)) { + packetSize = "1000"; + } + + LiteClientConfig weMQProxyClientConfig = new LiteClientConfig(); + weMQProxyClientConfig.setRegistryEnabled(false) + .setRegistryAddr("http://127.0.0.1:8090") + .setLiteProxyAddr("127.0.0.1:10105") + .setEnv("A") + .setRegion("SZ") + .setIdc("FT") + .setDcn("AA0") + .setIp(IPUtil.getLocalAddress()) + .setSys("5147") + .setPid(String.valueOf(ThreadUtil.getPID())) + .setLiteProxyAddr(proxyIPPort); + LiteProducer liteProducer = new LiteProducer(weMQProxyClientConfig); + liteProducer.start(); + for (int i = 1; i < 10; i++) { + LiteMessage liteMessage = new LiteMessage(); + liteMessage.setBizSeqNo(RandomStringUtils.randomNumeric(30)) + .setContent("contentStr with special protocal") + .setTopic(topic) + .setUniqueId(RandomStringUtils.randomNumeric(30)) + .addProp(Constants.PROXY_MESSAGE_CONST_TTL, String.valueOf(4 * 3600 * 1000)); + + boolean flag = liteProducer.publish(liteMessage); + Thread.sleep(1000); + logger.info("publish result , {}", flag); + } + } + +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/http/demo/AsyncSyncRequestInstance.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/http/demo/AsyncSyncRequestInstance.java new file mode 100644 index 0000000000..454cff815a --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/http/demo/AsyncSyncRequestInstance.java @@ -0,0 +1,141 @@ +package cn.webank.eventmesh.client.http.demo; +import cn.webank.eventmesh.client.http.conf.LiteClientConfig; +import cn.webank.eventmesh.client.http.producer.LiteProducer; +import cn.webank.eventmesh.client.http.producer.RRCallback; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.LiteMessage; +import cn.webank.eventmesh.common.ThreadPoolFactory; +import cn.webank.eventmesh.common.ThreadUtil; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +public class AsyncSyncRequestInstance { + + public static Logger logger = LoggerFactory.getLogger(SyncRequestInstance.class); + + private static AtomicLong httpRequestPerSecond = new AtomicLong(0); + + private static LinkedList httpRequestTPSSnapshots = new LinkedList(); + + private static AtomicLong httpResPerSecond = new AtomicLong(0); + + private static LinkedList httpResTPSSnapshots = new LinkedList(); + + public static ScheduledExecutorService serviceRegistryScheduler = + ThreadPoolFactory.createSingleScheduledExecutor("proxy-sdk-stat-"); + + public static void main(String[] args) throws Exception { + + serviceRegistryScheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + snapshotHTTPTPS(); + } + }, 0, 1000, TimeUnit.MILLISECONDS); + + serviceRegistryScheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + logger.info("TPS, request tps:{}, response tps:{}", + avgTps(httpRequestTPSSnapshots), avgTps(httpResTPSSnapshots)); + } + }, 0, 30000, TimeUnit.MILLISECONDS); + + String confCenterAddr = args[0]; + + String proxyIPPort = args[1]; + + final String topic = args[2]; + + String packetSize = args[3]; + + if (StringUtils.isBlank(confCenterAddr)) { + confCenterAddr = "http://127.0.0.1:8090"; + } + + if (StringUtils.isBlank(proxyIPPort)) { + proxyIPPort = "127.0.0.1:10105"; + } + + if (StringUtils.isBlank(packetSize)) { + packetSize = "1000"; + } + + LiteClientConfig weMQProxyClientConfig = new LiteClientConfig(); + weMQProxyClientConfig.setRegistryEnabled(false) + .setRegistryAddr("http://127.0.0.1:8090") + .setLiteProxyAddr("127.0.0.1:10105") + .setEnv("A") + .setRegion("SZ") + .setIdc("FT") + .setDcn("AA0") + .setIp(IPUtil.getLocalAddress()) + .setSys("5147") + .setPid(String.valueOf(ThreadUtil.getPID())) + .setLiteProxyAddr(proxyIPPort); + + final LiteProducer liteProducer = new LiteProducer(weMQProxyClientConfig); + + while (true) { + final long startTime = System.currentTimeMillis(); + final LiteMessage liteMessage = new LiteMessage(); + liteMessage.setBizSeqNo(RandomStringUtils.randomNumeric(30)) + .setContent("contentStr with special protocal") + .setTopic(topic) + .setUniqueId(RandomStringUtils.randomNumeric(30)); + + try { + liteProducer.request(liteMessage, new RRCallback() { + @Override + public void onSuccess(LiteMessage o) { + httpResPerSecond.incrementAndGet(); + logger.debug("sendmsg : {}, return : {}, cost:{}ms", liteMessage.getContent(), System.currentTimeMillis() - startTime); + } + + @Override + public void onException(Throwable e) { + httpResPerSecond.incrementAndGet(); + logger.debug("", e); + } + }, 3000); + httpRequestPerSecond.incrementAndGet(); + + Thread.sleep(2000); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public static void snapshotHTTPTPS() { + Integer tps = httpRequestPerSecond.intValue(); + httpRequestTPSSnapshots.add(tps); + httpRequestPerSecond.set(0); + if (httpRequestTPSSnapshots.size() > 30) { + httpRequestTPSSnapshots.removeFirst(); + } + + Integer resTps = httpResPerSecond.intValue(); + httpResTPSSnapshots.add(resTps); + httpResPerSecond.set(0); + if (httpResTPSSnapshots.size() > 30) { + httpResTPSSnapshots.removeFirst(); + } + } + + private static int avgTps(LinkedList list) { + int sum = 0; + for (Integer i : list) { + sum = sum + i.intValue(); + } + return (int) sum / list.size(); + } + +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/http/demo/SyncRequestInstance.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/http/demo/SyncRequestInstance.java new file mode 100644 index 0000000000..9280d7feef --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/http/demo/SyncRequestInstance.java @@ -0,0 +1,144 @@ +package cn.webank.eventmesh.client.http.demo; +import cn.webank.eventmesh.client.http.conf.LiteClientConfig; +import cn.webank.eventmesh.client.http.producer.LiteProducer; +import cn.webank.eventmesh.common.IPUtil; +import cn.webank.eventmesh.common.LiteMessage; +import cn.webank.eventmesh.common.ThreadPoolFactory; +import cn.webank.eventmesh.common.ThreadUtil; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +public class SyncRequestInstance { + + public static Logger logger = LoggerFactory.getLogger(SyncRequestInstance.class); + + private static AtomicLong httpRequestPerSecond = new AtomicLong(0); + + private static LinkedList httpRequestTPSSnapshots = new LinkedList(); + + private static AtomicLong httpResPerSecond = new AtomicLong(0); + + private static LinkedList httpResTPSSnapshots = new LinkedList(); + + public static ScheduledExecutorService serviceRegistryScheduler = + ThreadPoolFactory.createSingleScheduledExecutor("proxy-sdk-stat-"); + + public static void main(String[] args) throws Exception { + + serviceRegistryScheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + snapshotHTTPTPS(); + } + }, 0, 1000, TimeUnit.MILLISECONDS); + + serviceRegistryScheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + logger.info("TPS, request tps:{}, response tps:{}", + avgTps(httpRequestTPSSnapshots), avgTps(httpResTPSSnapshots)); + } + }, 0, 30000, TimeUnit.MILLISECONDS); + + String confCenterAddr = args[0]; + + String proxyIPPort = args[1]; + + final String topic = args[2]; + + String packetSize = args[3]; + + String threads = args[4]; + + if (StringUtils.isBlank(confCenterAddr)) { + confCenterAddr = "http://127.0.0.1:8090"; + } + + if (StringUtils.isBlank(proxyIPPort)) { + proxyIPPort = "127.0.0.1:10105"; + } + + if (StringUtils.isBlank(packetSize)) { + packetSize = "1000"; + } + + if (StringUtils.isBlank(threads)) { + threads = "1"; + } + + LiteClientConfig weMQProxyClientConfig = new LiteClientConfig(); + weMQProxyClientConfig.setRegistryEnabled(false) + .setRegistryAddr("http://127.0.0.1:8090") + .setLiteProxyAddr("127.0.0.1:10105") + .setEnv("A") + .setRegion("SZ") + .setIdc("FT") + .setDcn("AA0") + .setIp(IPUtil.getLocalAddress()) + .setSys("5147") + .setPid(String.valueOf(ThreadUtil.getPID())) + .setLiteProxyAddr(proxyIPPort); + + final LiteProducer proxyProducer = new LiteProducer(weMQProxyClientConfig); + proxyProducer.start(); + for (int i = 0; i < Integer.valueOf(threads); i++) { + new Thread(new Runnable() { + @Override + public void run() { + while (true) { + long startTime = System.currentTimeMillis(); + LiteMessage liteMessage = new LiteMessage(); + liteMessage.setBizSeqNo(RandomStringUtils.randomNumeric(30)) + .setContent("contentStr with special protocal") + .setTopic(topic) + .setUniqueId(RandomStringUtils.randomNumeric(30)); + + try { + LiteMessage rtn = proxyProducer.request(liteMessage, 10000); + if (logger.isDebugEnabled()) { + logger.debug("sendmsg : {}, return : {}, cost:{}ms", liteMessage.getContent(), rtn.getContent(), System.currentTimeMillis() - startTime); + } + httpResPerSecond.incrementAndGet(); + httpRequestPerSecond.incrementAndGet(); + + Thread.sleep(2000); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + }, "sync-requestor-" + i).start(); + } + } + + public static void snapshotHTTPTPS() { + Integer tps = httpRequestPerSecond.intValue(); + httpRequestTPSSnapshots.add(tps); + httpRequestPerSecond.set(0); + if (httpRequestTPSSnapshots.size() > 30) { + httpRequestTPSSnapshots.removeFirst(); + } + + Integer resTps = httpResPerSecond.intValue(); + httpResTPSSnapshots.add(resTps); + httpResPerSecond.set(0); + if (httpResTPSSnapshots.size() > 30) { + httpResTPSSnapshots.removeFirst(); + } + } + + private static int avgTps(LinkedList list) { + int sum = 0; + for (Integer i : list) { + sum = sum + i.intValue(); + } + return (int) sum / list.size(); + } +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/common/AccessTestCaseTopicSet.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/common/AccessTestCaseTopicSet.java new file mode 100644 index 0000000000..8ab10f1c99 --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/common/AccessTestCaseTopicSet.java @@ -0,0 +1,14 @@ +package cn.webank.eventmesh.client.tcp.common; + +/** + * Testcase set + */ +public class AccessTestCaseTopicSet { + + public static final String TOPIC_PRX_WQ2ClientBroadCast = "topic-broadcast-test"; + + public static final String TOPIC_PRX_SyncSubscribeTest = "topic-sync-test"; + + public static final String TOPIC_PRX_WQ2ClientUniCast = "topic-async-test"; + +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/common/AccessTestUtils.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/common/AccessTestUtils.java new file mode 100644 index 0000000000..9f0961da0b --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/common/AccessTestUtils.java @@ -0,0 +1,150 @@ +<<<<<<<< HEAD:eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/common/AccessTestUtils.java +package cn.webank.eventmesh.client.tcp.common; +======== +package org.apache.eventmesh.client.tcp.common; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestUtils.java + +<<<<<<<< HEAD:eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/common/AccessTestUtils.java +import cn.webank.eventmesh.common.protocol.tcp.AccessMessage; +import cn.webank.eventmesh.common.protocol.tcp.Command; +import cn.webank.eventmesh.common.protocol.tcp.Header; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; + +import java.util.concurrent.ThreadLocalRandom; + +import static cn.webank.eventmesh.client.tcp.common.AccessTestCaseTopicSet.*; +import static cn.webank.eventmesh.common.protocol.tcp.Command.RESPONSE_TO_SERVER; +======== +import com.webank.eventmesh.common.protocol.tcp.EventMeshMessage; +import com.webank.eventmesh.common.protocol.tcp.Command; +import com.webank.eventmesh.common.protocol.tcp.Header; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; + +import java.util.concurrent.ThreadLocalRandom; + +import static com.webank.eventmesh.common.protocol.tcp.Command.RESPONSE_TO_SERVER; +<<<<<<<< HEAD:eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/common/AccessTestUtils.java +>>>>>>>> 4ed546fd7 ([ISSUE #265]rename wemq and access to eventmesh):eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/common/EventMeshTestUtils.java +======== +import static org.apache.eventmesh.client.tcp.common.EventMeshTestCaseTopicSet.*; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestUtils.java + +public class EventMeshTestUtils { + private static final int seqLength = 10; + + public static UserAgent generateClient1() { + UserAgent user = new UserAgent(); + user.setDcn("AC0"); + user.setHost("127.0.0.1"); + user.setPassword(generateRandomString(8)); + user.setUsername("PU4283"); + user.setPath("/data/app/umg_proxy"); + user.setPort(8362); + user.setSubsystem("5023"); + user.setPid(32893); + user.setVersion("2.0.11"); + user.setIdc("FT"); + return user; + } + + public static UserAgent generateClient2() { + UserAgent user = new UserAgent(); + user.setDcn("AC0"); + user.setHost("127.0.0.1"); + user.setPassword(generateRandomString(8)); + user.setUsername("PU4283"); + user.setPath("/data/app/umg_proxy"); + user.setPort(9362); + user.setSubsystem("5017"); + user.setPid(42893); + user.setVersion("2.0.11"); + user.setIdc("FT"); + return user; + } + + public static Package syncRR() { + Package msg = new Package(); + msg.setHeader(new Header(Command.REQUEST_TO_SERVER, 0, null, generateRandomString(seqLength))); + msg.setBody(generateSyncRRMqMsg()); + return msg; + } + + public static Package asyncRR() { + Package msg = new Package(); + msg.setHeader(new Header(Command.REQUEST_TO_SERVER, 0, null, generateRandomString(seqLength))); + msg.setBody(generateAsyncRRMqMsg()); + return msg; + } + + public static Package asyncMessage() { + Package msg = new Package(); + msg.setHeader(new Header(Command.ASYNC_MESSAGE_TO_SERVER, 0, null, generateRandomString(seqLength))); + msg.setBody(generateAsyncEventMqMsg()); + return msg; + } + + public static Package broadcastMessage() { + Package msg = new Package(); + msg.setHeader(new Header(Command.BROADCAST_MESSAGE_TO_SERVER, 0, null, generateRandomString(seqLength))); + msg.setBody(generateBroadcastMqMsg()); + return msg; + } + + public static Package rrResponse(Package request) { + Package msg = new Package(); + msg.setHeader(new Header(RESPONSE_TO_SERVER, 0, null, generateRandomString(seqLength))); + msg.setBody(request.getBody()); + return msg; + } + + private static EventMeshMessage generateSyncRRMqMsg() { + EventMeshMessage mqMsg = new EventMeshMessage(); + mqMsg.setTopic(TOPIC_PRX_SyncSubscribeTest); + mqMsg.getProperties().put("msgType", "persistent"); + mqMsg.getProperties().put("TTL", "300000"); + mqMsg.getProperties().put("KEYS", generateRandomString(16)); + mqMsg.setBody("testSyncRR"); + return mqMsg; + } + + + private static EventMeshMessage generateAsyncRRMqMsg() { + EventMeshMessage mqMsg = new EventMeshMessage(); + mqMsg.setTopic(TOPIC_PRX_SyncSubscribeTest); + mqMsg.getProperties().put("REPLY_TO", "10.36.0.109@ProducerGroup-producerPool-9-access#V1_4_0#CI"); + mqMsg.getProperties().put("TTL", "300000"); + mqMsg.getProperties().put("PROPERTY_MESSAGE_REPLY_TO", "notnull"); + mqMsg.setBody("testAsyncRR"); + return mqMsg; + } + + private static EventMeshMessage generateAsyncEventMqMsg() { + EventMeshMessage mqMsg = new EventMeshMessage(); + mqMsg.setTopic(TOPIC_PRX_WQ2ClientUniCast); + mqMsg.getProperties().put("REPLY_TO", "10.36.0.109@ProducerGroup-producerPool-9-access#V1_4_0#CI"); + mqMsg.getProperties().put("TTL", "30000"); + mqMsg.getProperties().put("PROPERTY_MESSAGE_REPLY_TO", "notnull"); + mqMsg.setBody("testAsyncMessage"); + return mqMsg; + } + + private static EventMeshMessage generateBroadcastMqMsg() { + EventMeshMessage mqMsg = new EventMeshMessage(); + mqMsg.setTopic(TOPIC_PRX_WQ2ClientBroadCast); + mqMsg.getProperties().put("REPLY_TO", "10.36.0.109@ProducerGroup-producerPool-9-access#V1_4_0#CI"); + mqMsg.getProperties().put("TTL", "30000"); + mqMsg.getProperties().put("PROPERTY_MESSAGE_REPLY_TO", "notnull"); + mqMsg.setBody("testAsyncMessage"); + return mqMsg; + } + + private static String generateRandomString(int length) { + StringBuilder builder = new StringBuilder(length); + for (int i = 0; i < length; i++) { + builder.append((char) ThreadLocalRandom.current().nextInt(48, 57)); + } + return builder.toString(); + } +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncPublish.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncPublish.java new file mode 100644 index 0000000000..4543485b84 --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncPublish.java @@ -0,0 +1,38 @@ +package cn.webank.eventmesh.client.tcp.demo; + +import cn.webank.eventmesh.client.tcp.WemqAccessClient; +import cn.webank.eventmesh.client.tcp.common.AccessTestUtils; +import cn.webank.eventmesh.client.tcp.common.WemqAccessCommon; +import cn.webank.eventmesh.client.tcp.impl.DefaultWemqAccessClient; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AsyncPublish{ + + public static Logger logger = LoggerFactory.getLogger(AsyncPublish.class); + + private static WemqAccessClient client; + + public static AsyncPublish handler = new AsyncPublish(); + + public static void main(String[] agrs)throws Exception{ + try{ + UserAgent userAgent = AccessTestUtils.generateClient1(); + client = new DefaultWemqAccessClient("127.0.0.1",10000,userAgent); + client.init(); + client.heartbeat(); + + Package asyncMsg = AccessTestUtils.asyncMessage(); + logger.info("开始发送异步单播消息:{}", asyncMsg); + client.publish(asyncMsg, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + + Thread.sleep(2000); + //退出,销毁资源 +// client.close(); + }catch (Exception e){ + logger.warn("AsyncPublish failed", e); + } + } +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncPublishBroadcast.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncPublishBroadcast.java new file mode 100644 index 0000000000..18102cfb19 --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncPublishBroadcast.java @@ -0,0 +1,36 @@ +package cn.webank.eventmesh.client.tcp.demo; + +import cn.webank.eventmesh.client.tcp.WemqAccessClient; +import cn.webank.eventmesh.client.tcp.common.AccessTestUtils; +import cn.webank.eventmesh.client.tcp.common.WemqAccessCommon; +import cn.webank.eventmesh.client.tcp.impl.DefaultWemqAccessClient; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AsyncPublishBroadcast { + + public static Logger logger = LoggerFactory.getLogger(AsyncPublishBroadcast.class); + + private static WemqAccessClient client; + + public static void main(String[] agrs)throws Exception{ + try{ + UserAgent userAgent = AccessTestUtils.generateClient1(); + client = new DefaultWemqAccessClient("127.0.0.1",10002,userAgent); + client.init(); + client.heartbeat(); + + Package broadcastMsg = AccessTestUtils.broadcastMessage(); + logger.info("开始发送广播消息:{}", broadcastMsg); + client.broadcast(broadcastMsg, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + + Thread.sleep(2000); + //退出,销毁资源 +// client.close(); + }catch (Exception e){ + logger.warn("AsyncPublishBroadcast failed", e); + } + } +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncSubscribe.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncSubscribe.java new file mode 100644 index 0000000000..289a202851 --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncSubscribe.java @@ -0,0 +1,48 @@ +package cn.webank.eventmesh.client.tcp.demo; + +import cn.webank.eventmesh.client.tcp.WemqAccessClient; +import cn.webank.eventmesh.client.tcp.common.AccessTestUtils; +import cn.webank.eventmesh.client.tcp.common.ReceiveMsgHook; +import cn.webank.eventmesh.client.tcp.impl.DefaultWemqAccessClient; +import cn.webank.eventmesh.common.protocol.tcp.AccessMessage; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import io.netty.channel.ChannelHandlerContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AsyncSubscribe implements ReceiveMsgHook{ + + public static Logger logger = LoggerFactory.getLogger(AsyncSubscribe.class); + + private static WemqAccessClient client; + + public static AsyncSubscribe handler = new AsyncSubscribe(); + + public static void main(String[] agrs)throws Exception{ + try{ + UserAgent userAgent = AccessTestUtils.generateClient2(); + client = new DefaultWemqAccessClient("127.0.0.1",10002,userAgent); + client.init(); + client.heartbeat(); + + client.subscribe("FT0-e-80010000-01-1"); + client.registerSubBusiHandler(handler); + + client.listen(); + + //client.unsubscribe(); + + //退出,销毁资源 +// client.close(); + }catch (Exception e){ + logger.warn("AsyncSubscribe failed", e); + } + } + + @Override + public void handle(Package msg, ChannelHandlerContext ctx) { + AccessMessage accessMessage = (AccessMessage)msg.getBody(); + logger.info("sub收到异步单播消息:{}", accessMessage); + } +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncSubscribeBroadcast.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncSubscribeBroadcast.java new file mode 100644 index 0000000000..36f220d57a --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/AsyncSubscribeBroadcast.java @@ -0,0 +1,48 @@ +package cn.webank.eventmesh.client.tcp.demo; + +import cn.webank.eventmesh.client.tcp.WemqAccessClient; +import cn.webank.eventmesh.client.tcp.common.AccessTestUtils; +import cn.webank.eventmesh.client.tcp.common.ReceiveMsgHook; +import cn.webank.eventmesh.client.tcp.impl.DefaultWemqAccessClient; +import cn.webank.eventmesh.common.protocol.tcp.AccessMessage; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import io.netty.channel.ChannelHandlerContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AsyncSubscribeBroadcast implements ReceiveMsgHook{ + + public static Logger logger = LoggerFactory.getLogger(AsyncSubscribeBroadcast.class); + + private static WemqAccessClient client; + + public static AsyncSubscribeBroadcast handler = new AsyncSubscribeBroadcast(); + + public static void main(String[] agrs)throws Exception{ + try{ + UserAgent userAgent = AccessTestUtils.generateClient2(); + client = new DefaultWemqAccessClient("127.0.0.1",10002,userAgent); + client.init(); + client.heartbeat(); + + client.subscribe("FT0-e-80030001-01-3"); + client.registerSubBusiHandler(handler); + + client.listen(); + + //client.unsubscribe(); + + //退出,销毁资源 +// client.close(); + }catch (Exception e){ + logger.warn("AsyncSubscribeBroadcast failed", e); + } + } + + @Override + public void handle(Package msg, ChannelHandlerContext ctx) { + AccessMessage accessMessage = (AccessMessage)msg.getBody(); + logger.info("sub收到广播消息:{}", accessMessage); + } +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/SyncRequest.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/SyncRequest.java new file mode 100644 index 0000000000..96cb070469 --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/SyncRequest.java @@ -0,0 +1,36 @@ +package cn.webank.eventmesh.client.tcp.demo; + +import cn.webank.eventmesh.client.tcp.WemqAccessClient; +import cn.webank.eventmesh.client.tcp.common.AccessTestUtils; +import cn.webank.eventmesh.client.tcp.common.WemqAccessCommon; +import cn.webank.eventmesh.client.tcp.impl.DefaultWemqAccessClient; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SyncRequest { + + public static Logger logger = LoggerFactory.getLogger(SyncRequest.class); + + private static WemqAccessClient client; + + public static void main(String[] agrs)throws Exception{ + try{ + UserAgent userAgent = AccessTestUtils.generateClient1(); + client = new DefaultWemqAccessClient("127.0.0.1",10000,userAgent); + client.init(); + client.heartbeat(); + + Package rrMsg = AccessTestUtils.syncRR(); + logger.info("开始发送同步RR消息:{}",rrMsg); + Package response = client.rr(rrMsg, WemqAccessCommon.DEFAULT_TIME_OUT_MILLS); + logger.info("收到同步RR回包:{}",response); + + //退出,销毁资源 +// client.close(); + }catch (Exception e){ + logger.warn("SyncRequest failed", e); + } + } +} diff --git a/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/SyncResponse.java b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/SyncResponse.java new file mode 100644 index 0000000000..8d4e13a617 --- /dev/null +++ b/eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/SyncResponse.java @@ -0,0 +1,60 @@ +<<<<<<<< HEAD:eventmesh-sdk-java/src/test/java/cn/webank/eventmesh/client/tcp/demo/SyncResponse.java +package cn.webank.eventmesh.client.tcp.demo; + +import cn.webank.eventmesh.client.tcp.WemqAccessClient; +import cn.webank.eventmesh.client.tcp.common.AccessTestUtils; +import cn.webank.eventmesh.client.tcp.common.ReceiveMsgHook; +import cn.webank.eventmesh.client.tcp.impl.DefaultWemqAccessClient; +import cn.webank.eventmesh.common.protocol.tcp.Package; +import cn.webank.eventmesh.common.protocol.tcp.UserAgent; +======== +package org.apache.eventmesh.client.tcp.demo; + +import org.apache.eventmesh.client.tcp.EventMeshClient; +import org.apache.eventmesh.client.tcp.common.EventMeshTestUtils; +import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; +import org.apache.eventmesh.client.tcp.impl.DefaultEventMeshClient; +import com.webank.eventmesh.common.protocol.tcp.Package; +import com.webank.eventmesh.common.protocol.tcp.UserAgent; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/demo/SyncResponse.java +import io.netty.channel.ChannelHandlerContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SyncResponse implements ReceiveMsgHook{ + + public static Logger logger = LoggerFactory.getLogger(SyncResponse.class); + + private static WemqAccessClient client; + + public static SyncResponse handler = new SyncResponse(); + + public static void main(String[] agrs)throws Exception{ + try{ + UserAgent userAgent = AccessTestUtils.generateClient2(); + client = new DefaultWemqAccessClient("127.0.0.1",10000,userAgent); + client.init(); + client.heartbeat(); + + client.subscribe("FT0-s-80000000-01-0"); + //同步RR消息 + client.registerSubBusiHandler(handler); + + client.listen(); + + //client.unsubscribe(); + + //退出,销毁资源 +// client.close(); + }catch (Exception e){ + logger.warn("SyncResponse failed", e); + } + } + + @Override + public void handle(Package msg, ChannelHandlerContext ctx) { + logger.info("sub收到消息:{}", msg); + Package pkg = AccessTestUtils.rrResponse(msg); + ctx.writeAndFlush(pkg); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java index d435f6751e..352934f0b1 100644 --- a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java @@ -16,6 +16,10 @@ */ package org.apache.eventmesh.client.tcp.common; +<<<<<<<< HEAD:eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java +======== +import com.webank.eventmesh.common.protocol.tcp.Package; +>>>>>>>> 4bc230e32 (refactor(eventmesh-sdk-java):rename to org.apache(#281)):eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java /** * AsyncRRCallback diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPClient.java deleted file mode 100644 index dce45bf24c..0000000000 --- a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPClient.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.eventmesh.client.tcp.impl.cloudevent; - -import org.apache.eventmesh.client.tcp.EventMeshTCPClient; -import org.apache.eventmesh.client.tcp.EventMeshTCPPubClient; -import org.apache.eventmesh.client.tcp.EventMeshTCPSubClient; -import org.apache.eventmesh.client.tcp.common.AsyncRRCallback; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.common.protocol.tcp.Package; - -import io.cloudevents.CloudEvent; - -public class CloudEventTCPClient implements EventMeshTCPClient { - - private final CloudEventTCPPubClient cloudEventTCPPubClient; - - private final CloudEventTCPSubClient cloudEventTCPSubClient; - - public CloudEventTCPClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { - cloudEventTCPPubClient = new CloudEventTCPPubClient(eventMeshTcpClientConfig); - cloudEventTCPSubClient = new CloudEventTCPSubClient(eventMeshTcpClientConfig); - } - - @Override - public void init() throws EventMeshException { - cloudEventTCPPubClient.init(); - cloudEventTCPSubClient.init(); - } - - @Override - public Package rr(CloudEvent cloudEvent, long timeout) throws EventMeshException { - return cloudEventTCPPubClient.rr(cloudEvent, timeout); - } - - @Override - public void asyncRR(CloudEvent cloudEvent, AsyncRRCallback callback, long timeout) throws EventMeshException { - cloudEventTCPPubClient.asyncRR(cloudEvent, callback, timeout); - } - - @Override - public Package publish(CloudEvent cloudEvent, long timeout) throws EventMeshException { - return cloudEventTCPPubClient.publish(cloudEvent, timeout); - } - - @Override - public void broadcast(CloudEvent cloudEvent, long timeout) throws EventMeshException { - cloudEventTCPPubClient.broadcast(cloudEvent, timeout); - } - - @Override - public void listen() throws EventMeshException { - cloudEventTCPSubClient.listen(); - } - - @Override - public void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException { - cloudEventTCPSubClient.subscribe(topic, subscriptionMode, subscriptionType); - } - - @Override - public void unsubscribe() throws EventMeshException { - cloudEventTCPSubClient.unsubscribe(); - } - - @Override - public void registerPubBusiHandler(ReceiveMsgHook handler) throws EventMeshException { - cloudEventTCPPubClient.registerBusiHandler(handler); - } - - @Override - public void registerSubBusiHandler(ReceiveMsgHook handler) throws EventMeshException { - cloudEventTCPSubClient.registerBusiHandler(handler); - } - - @Override - public void close() throws EventMeshException { - this.cloudEventTCPPubClient.close(); - this.cloudEventTCPSubClient.close(); - } - - @Override - public EventMeshTCPPubClient getPubClient() { - return cloudEventTCPPubClient; - } - - @Override - public EventMeshTCPSubClient getSubClient() { - return cloudEventTCPSubClient; - } -} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPPubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPPubClient.java deleted file mode 100644 index 35f2186b34..0000000000 --- a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPPubClient.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.eventmesh.client.tcp.impl.cloudevent; - -import org.apache.eventmesh.client.tcp.EventMeshTCPPubClient; -import org.apache.eventmesh.client.tcp.common.AsyncRRCallback; -import org.apache.eventmesh.client.tcp.common.MessageUtils; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.RequestContext; -import org.apache.eventmesh.client.tcp.common.TcpClient; -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.client.tcp.impl.AbstractEventMeshTCPPubHandler; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.Package; - -import java.nio.charset.StandardCharsets; -import java.util.concurrent.ConcurrentHashMap; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.format.EventFormat; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.jackson.JsonFormat; -import io.netty.channel.ChannelHandler.Sharable; -import io.netty.channel.ChannelHandlerContext; - -import com.google.common.base.Preconditions; - -import lombok.extern.slf4j.Slf4j; - -/** - * A CloudEvent TCP publish client implementation. - */ -@Slf4j -class CloudEventTCPPubClient extends TcpClient implements EventMeshTCPPubClient { - - private ReceiveMsgHook callback; - - private final ConcurrentHashMap callbackConcurrentHashMap = new ConcurrentHashMap<>(); - - public CloudEventTCPPubClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { - super(eventMeshTcpClientConfig); - } - - @Override - public void init() throws EventMeshException { - try { - super.open(new CloudEventTCPPubHandler(contexts)); - super.hello(); - super.heartbeat(); - } catch (Exception ex) { - throw new EventMeshException("Initialize EventMeshMessageTCPPubClient error", ex); - } - } - - @Override - public void reconnect() throws EventMeshException { - try { - super.reconnect(); - super.hello(); - } catch (Exception ex) { - throw new EventMeshException("reconnect error", ex); - } - } - - @Override - public Package rr(CloudEvent event, long timeout) throws EventMeshException { - try { - Package msg = MessageUtils.buildPackage(event, Command.REQUEST_TO_SERVER); - log.info("{}|rr|send|type={}|msg={}", CLIENTNO, msg, msg); - return io(msg, timeout); - } catch (Exception ex) { - throw new EventMeshException("rr error", ex); - } - } - - @Override - public void asyncRR(CloudEvent event, AsyncRRCallback callback, long timeout) throws EventMeshException { - try { - Package msg = MessageUtils.buildPackage(event, Command.REQUEST_TO_SERVER); - super.send(msg); - this.callbackConcurrentHashMap.put((String) RequestContext.key(msg), callback); - } catch (Exception ex) { - throw new EventMeshException("asyncRR error", ex); - } - } - - @Override - public Package publish(CloudEvent cloudEvent, long timeout) throws EventMeshException { - try { - Package msg = MessageUtils.buildPackage(cloudEvent, Command.ASYNC_MESSAGE_TO_SERVER); - log.info("SimplePubClientImpl cloud event|{}|publish|send|type={}|protocol={}|msg={}", - CLIENTNO, msg.getHeader().getCmd(), msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); - return io(msg, timeout); - } catch (Exception ex) { - throw new EventMeshException("publish error", ex); - } - } - - @Override - public void broadcast(CloudEvent cloudEvent, long timeout) throws EventMeshException { - try { - Package msg = MessageUtils.buildPackage(cloudEvent, Command.BROADCAST_MESSAGE_TO_SERVER); - log.info("{}|publish|send|type={}|protocol={}|msg={}", CLIENTNO, msg.getHeader().getCmd(), - msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); - super.send(msg); - } catch (Exception ex) { - throw new EventMeshException("Broadcast message error", ex); - } - } - - @Override - public void registerBusiHandler(ReceiveMsgHook handler) throws EventMeshException { - callback = handler; - } - - @Override - public void close() { - try { - super.close(); - } catch (Exception ex) { - log.error("Close CloudEvent TCP publish client error", ex); - } - } - - @Sharable - private class CloudEventTCPPubHandler extends AbstractEventMeshTCPPubHandler { - - public CloudEventTCPPubHandler(ConcurrentHashMap contexts) { - super(contexts); - } - - @Override - public void callback(CloudEvent cloudEvent, ChannelHandlerContext ctx) { - if (callback != null) { - callback.handle(cloudEvent) - .ifPresent(responseMessage -> ctx.writeAndFlush(MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER))); - } - } - - @Override - public CloudEvent getMessage(Package tcpPackage) { - EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE); - Preconditions.checkNotNull(eventFormat, - String.format("Cannot find the cloudevent format: %s", JsonFormat.CONTENT_TYPE)); - return eventFormat.deserialize(tcpPackage.getBody().toString().getBytes(StandardCharsets.UTF_8)); - } - - @Override - public void sendResponse(Package tcpPackage) { - try { - send(tcpPackage); - } catch (Exception exception) { - throw new RuntimeException(exception); - } - } - } -} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPSubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPSubClient.java deleted file mode 100644 index 585a58b878..0000000000 --- a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPSubClient.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.eventmesh.client.tcp.impl.cloudevent; - -import org.apache.eventmesh.client.tcp.EventMeshTCPSubClient; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.client.tcp.common.MessageUtils; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.RequestContext; -import org.apache.eventmesh.client.tcp.common.TcpClient; -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.client.tcp.impl.AbstractEventMeshTCPSubHandler; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.Package; - -import org.apache.commons.collections4.CollectionUtils; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.format.EventFormat; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.jackson.JsonFormat; -import io.netty.channel.ChannelHandler.Sharable; -import io.netty.channel.ChannelHandlerContext; - -import com.google.common.base.Preconditions; - -import lombok.extern.slf4j.Slf4j; - -/** - * CloudEvent TCP subscribe client implementation. - */ -@Slf4j -class CloudEventTCPSubClient extends TcpClient implements EventMeshTCPSubClient { - - private final List subscriptionItems = Collections.synchronizedList(new ArrayList<>()); - private ReceiveMsgHook callback; - - public CloudEventTCPSubClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { - super(eventMeshTcpClientConfig); - } - - @Override - public void init() throws EventMeshException { - try { - open(new CloudEventTCPSubHandler(contexts)); - hello(); - heartbeat(); - log.info("SimpleSubClientImpl|{}|started!", CLIENTNO); - } catch (Exception ex) { - throw new EventMeshException("Initialize EventMeshMessageTcpSubClient error", ex); - } - } - - @Override - public void reconnect() throws EventMeshException { - try { - super.reconnect(); - hello(); - if (!CollectionUtils.isEmpty(subscriptionItems)) { - synchronized (subscriptionItems) { - for (SubscriptionItem item : subscriptionItems) { - Package request = MessageUtils.subscribe(item.getTopic(), item.getMode(), item.getType()); - this.io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - } - } - } - listen(); - } catch (Exception ex) { - // - } - } - - @Override - public void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException { - try { - subscriptionItems.add(new SubscriptionItem(topic, subscriptionMode, subscriptionType)); - Package request = MessageUtils.subscribe(topic, subscriptionMode, subscriptionType); - io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - } catch (Exception ex) { - throw new EventMeshException("Subscribe error", ex); - } - } - - @Override - public void unsubscribe() throws EventMeshException { - try { - Package request = MessageUtils.unsubscribe(); - io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - } catch (Exception ex) { - throw new EventMeshException("Unsubscribe error", ex); - } - } - - @Override - public void listen() throws EventMeshException { - try { - Package request = MessageUtils.listen(); - io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - } catch (Exception ex) { - throw new EventMeshException("Listen error", ex); - } - } - - @Override - public void registerBusiHandler(ReceiveMsgHook handler) throws EventMeshException { - this.callback = handler; - } - - @Override - public void close() { - try { - super.close(); - } catch (Exception ex) { - log.error("exception occurred when close", ex); - } - } - - @Sharable - private class CloudEventTCPSubHandler extends AbstractEventMeshTCPSubHandler { - - public CloudEventTCPSubHandler( - ConcurrentHashMap contexts) { - super(contexts); - } - - @Override - public CloudEvent getProtocolMessage(Package tcpPackage) { - EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE); - Preconditions.checkNotNull(eventFormat, - String.format("Cannot find the cloudevent format: %s", JsonFormat.CONTENT_TYPE)); - return eventFormat.deserialize(tcpPackage.getBody().toString().getBytes(StandardCharsets.UTF_8)); - } - - @Override - public void callback(CloudEvent cloudEvent, ChannelHandlerContext ctx) { - if (callback != null) { - callback.handle(cloudEvent).ifPresent( - responseMessage -> ctx.writeAndFlush(MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER))); - } - } - - @Override - public void response(Package tcpPackage) { - try { - send(tcpPackage); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - } -} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPClient.java deleted file mode 100644 index 1080926e21..0000000000 --- a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPClient.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.eventmesh.client.tcp.impl.eventmeshmessage; - -import static org.apache.commons.lang3.StringUtils.isNotBlank; - -import org.apache.eventmesh.client.tcp.EventMeshTCPClient; -import org.apache.eventmesh.client.tcp.EventMeshTCPPubClient; -import org.apache.eventmesh.client.tcp.EventMeshTCPSubClient; -import org.apache.eventmesh.client.tcp.common.AsyncRRCallback; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; -import org.apache.eventmesh.common.protocol.tcp.Package; - -import com.google.common.base.Preconditions; - -public class EventMeshMessageTCPClient implements EventMeshTCPClient { - - private final EventMeshTCPPubClient eventMeshMessageTCPPubClient; - private final EventMeshTCPSubClient eventMeshMessageTCPSubClient; - - public EventMeshMessageTCPClient(final EventMeshTCPClientConfig eventMeshTcpClientConfig) { - eventMeshMessageTCPPubClient = new EventMeshMessageTCPPubClient(eventMeshTcpClientConfig); - eventMeshMessageTCPSubClient = new EventMeshMessageTCPSubClient(eventMeshTcpClientConfig); - } - - @Override - public void init() throws EventMeshException { - eventMeshMessageTCPPubClient.init(); - eventMeshMessageTCPSubClient.init(); - } - - @Override - public Package rr(final EventMeshMessage eventMeshMessage, final long timeout) throws EventMeshException { - validateMessage(eventMeshMessage); - return eventMeshMessageTCPPubClient.rr(eventMeshMessage, timeout); - } - - @Override - public void asyncRR(final EventMeshMessage eventMeshMessage, final AsyncRRCallback callback, final long timeout) - throws EventMeshException { - validateMessage(eventMeshMessage); - eventMeshMessageTCPPubClient.asyncRR(eventMeshMessage, callback, timeout); - } - - @Override - public Package publish(final EventMeshMessage eventMeshMessage, final long timeout) throws EventMeshException { - validateMessage(eventMeshMessage); - return eventMeshMessageTCPPubClient.publish(eventMeshMessage, timeout); - } - - @Override - public void broadcast(final EventMeshMessage eventMeshMessage, final long timeout) throws EventMeshException { - validateMessage(eventMeshMessage); - eventMeshMessageTCPPubClient.broadcast(eventMeshMessage, timeout); - } - - @Override - public void listen() throws EventMeshException { - eventMeshMessageTCPSubClient.listen(); - } - - @Override - public void subscribe(final String topic, final SubscriptionMode subscriptionMode, - final SubscriptionType subscriptionType) - throws EventMeshException { - eventMeshMessageTCPSubClient.subscribe(topic, subscriptionMode, subscriptionType); - } - - @Override - public void unsubscribe() throws EventMeshException { - eventMeshMessageTCPSubClient.unsubscribe(); - } - - @Override - public void registerPubBusiHandler(final ReceiveMsgHook handler) throws EventMeshException { - eventMeshMessageTCPPubClient.registerBusiHandler(handler); - } - - @Override - public void registerSubBusiHandler(final ReceiveMsgHook handler) throws EventMeshException { - eventMeshMessageTCPSubClient.registerBusiHandler(handler); - } - - @Override - public void close() throws EventMeshException { - try { - this.eventMeshMessageTCPPubClient.close(); - } catch (Exception e) { - throw new EventMeshException(e); - } - - try { - this.eventMeshMessageTCPSubClient.close(); - } catch (Exception e) { - throw new EventMeshException(e); - } - } - - @Override - public EventMeshTCPPubClient getPubClient() { - return eventMeshMessageTCPPubClient; - } - - @Override - public EventMeshTCPSubClient getSubClient() { - return eventMeshMessageTCPSubClient; - } - - private void validateMessage(final EventMeshMessage message) { - Preconditions.checkNotNull(message, "Message cannot be null"); - Preconditions.checkArgument(isNotBlank(message.getTopic()), "Message's topic cannot be null and blank"); - Preconditions.checkArgument(isNotBlank(message.getBody()), "Message's body cannot be null and blank"); - } -} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPPubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPPubClient.java deleted file mode 100644 index 3d6af79e55..0000000000 --- a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPPubClient.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.eventmesh.client.tcp.impl.eventmeshmessage; - -import org.apache.eventmesh.client.tcp.EventMeshTCPPubClient; -import org.apache.eventmesh.client.tcp.common.AsyncRRCallback; -import org.apache.eventmesh.client.tcp.common.MessageUtils; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.RequestContext; -import org.apache.eventmesh.client.tcp.common.TcpClient; -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.client.tcp.impl.AbstractEventMeshTCPPubHandler; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.common.utils.JsonUtils; - -import java.util.concurrent.ConcurrentHashMap; - -import io.netty.channel.ChannelHandlerContext; - -import lombok.extern.slf4j.Slf4j; - -/** - * EventMeshMessage TCP publish client implementation. - */ -@Slf4j -class EventMeshMessageTCPPubClient extends TcpClient implements EventMeshTCPPubClient { - - private transient ReceiveMsgHook callback; - - private final transient ConcurrentHashMap callbackConcurrentHashMap = new ConcurrentHashMap<>(); - - public EventMeshMessageTCPPubClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { - super(eventMeshTcpClientConfig); - } - - @Override - public void init() throws EventMeshException { - try { - open(new EventMeshTCPPubHandler(contexts)); - hello(); - heartbeat(); - } catch (Exception e) { - throw new EventMeshException("Initialize EventMeshMessageTCPPubClient error", e); - } - - } - - @Override - public void reconnect() throws EventMeshException { - try { - super.reconnect(); - hello(); - } catch (Exception e) { - throw new EventMeshException("reconnect error", e); - } - } - - // todo: Maybe use org.apache.eventmesh.common.EvetMesh here is better - @Override - public Package rr(EventMeshMessage eventMeshMessage, long timeout) throws EventMeshException { - try { - Package msg = MessageUtils.buildPackage(eventMeshMessage, Command.REQUEST_TO_SERVER); - log.info("{}|rr|send|type={}|msg={}", CLIENTNO, msg, msg); - return io(msg, timeout); - } catch (Exception e) { - throw new EventMeshException("rr error", e); - } - } - - @Override - public void asyncRR(EventMeshMessage eventMeshMessage, AsyncRRCallback callback, long timeout) - throws EventMeshException { - try { - Package msg = MessageUtils.buildPackage(eventMeshMessage, Command.REQUEST_TO_SERVER); - super.send(msg); - this.callbackConcurrentHashMap.put((String) RequestContext.key(msg), callback); - } catch (Exception e) { - // should trigger callback? - throw new EventMeshException("asyncRR error", e); - } - } - - @Override - public Package publish(EventMeshMessage eventMeshMessage, long timeout) throws EventMeshException { - try { - Package msg = MessageUtils.buildPackage(eventMeshMessage, Command.ASYNC_MESSAGE_TO_SERVER); - log.info("SimplePubClientImpl em message|{}|publish|send|type={}|protocol={}|msg={}", - CLIENTNO, msg.getHeader().getCmd(), - msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); - return io(msg, timeout); - } catch (Exception e) { - throw new EventMeshException("publish error", e); - } - } - - @Override - public void broadcast(EventMeshMessage eventMeshMessage, long timeout) throws EventMeshException { - try { - // todo: transform EventMeshMessage to Package - Package msg = MessageUtils.buildPackage(eventMeshMessage, Command.BROADCAST_MESSAGE_TO_SERVER); - log.info("{}|publish|send|type={}|protocol={}|msg={}", CLIENTNO, msg.getHeader().getCmd(), - msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); - super.send(msg); - } catch (Exception e) { - throw new EventMeshException("Broadcast message error", e); - } - } - - @Override - public void registerBusiHandler(ReceiveMsgHook receiveMsgHook) throws EventMeshException { - this.callback = receiveMsgHook; - } - - @Override - public void close() { - try { - super.close(); - } catch (Exception e) { - log.error("Close EventMeshMessage TCP publish client error", e); - } - } - - private class EventMeshTCPPubHandler extends AbstractEventMeshTCPPubHandler { - - public EventMeshTCPPubHandler(ConcurrentHashMap contexts) { - super(contexts); - } - - @Override - public void callback(EventMeshMessage eventMeshMessage, ChannelHandlerContext ctx) { - if (callback != null) { - callback.handle(eventMeshMessage).ifPresent( - responseMessage -> ctx.writeAndFlush( - MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER))); - } - } - - @Override - public EventMeshMessage getMessage(Package tcpPackage) { - return JsonUtils.parseObject(tcpPackage.getBody().toString(), EventMeshMessage.class); - } - - @Override - public void sendResponse(Package tcpPackage) { - try { - send(tcpPackage); - } catch (Exception e) { - if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } else { - throw new RuntimeException(e); - } - } - } - } - -} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPSubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPSubClient.java deleted file mode 100644 index 7216597d7d..0000000000 --- a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPSubClient.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.eventmesh.client.tcp.impl.eventmeshmessage; - -import org.apache.eventmesh.client.tcp.EventMeshTCPSubClient; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.client.tcp.common.MessageUtils; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.RequestContext; -import org.apache.eventmesh.client.tcp.common.TcpClient; -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.client.tcp.impl.AbstractEventMeshTCPSubHandler; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.common.utils.JsonUtils; - -import org.apache.commons.collections4.CollectionUtils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; - -import io.netty.channel.ChannelHandlerContext; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -class EventMeshMessageTCPSubClient extends TcpClient implements EventMeshTCPSubClient { - - private final List subscriptionItems = Collections.synchronizedList(new ArrayList<>()); - private ReceiveMsgHook callback; - - public EventMeshMessageTCPSubClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { - super(eventMeshTcpClientConfig); - } - - @Override - public void init() throws EventMeshException { - try { - open(new EventMeshMessageTCPSubHandler(contexts)); - hello(); - heartbeat(); - log.info("SimpleSubClientImpl|{}|started!", CLIENTNO); - } catch (Exception ex) { - throw new EventMeshException("Initialize EventMeshMessageTcpSubClient error", ex); - } - } - - @Override - public void reconnect() throws EventMeshException { - try { - super.reconnect(); - hello(); - if (!CollectionUtils.isEmpty(subscriptionItems)) { - synchronized (subscriptionItems) { - for (SubscriptionItem item : subscriptionItems) { - Package request = MessageUtils.subscribe(item.getTopic(), item.getMode(), item.getType()); - this.io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - } - } - } - listen(); - } catch (Exception ex) { - // - } - } - - @Override - public void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException { - try { - subscriptionItems.add(new SubscriptionItem(topic, subscriptionMode, subscriptionType)); - Package request = MessageUtils.subscribe(topic, subscriptionMode, subscriptionType); - io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - } catch (Exception ex) { - throw new EventMeshException("Subscribe error", ex); - } - } - - @Override - public void unsubscribe() throws EventMeshException { - try { - Package request = MessageUtils.unsubscribe(); - io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - } catch (Exception ex) { - throw new EventMeshException("Unsubscribe error", ex); - } - } - - public void listen() throws EventMeshException { - try { - Package request = MessageUtils.listen(); - io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - } catch (Exception ex) { - throw new EventMeshException("Listen error", ex); - } - } - - @Override - public void registerBusiHandler(ReceiveMsgHook receiveMsgHook) throws EventMeshException { - this.callback = receiveMsgHook; - } - - @Override - public void close() { - try { - super.close(); - } catch (Exception ex) { - log.error("exception occurred when close.", ex); - } - } - - private class EventMeshMessageTCPSubHandler extends AbstractEventMeshTCPSubHandler { - - public EventMeshMessageTCPSubHandler(ConcurrentHashMap contexts) { - super(contexts); - } - - @Override - public EventMeshMessage getProtocolMessage(Package tcpPackage) { - return JsonUtils.parseObject(tcpPackage.getBody().toString(), EventMeshMessage.class); - } - - @Override - public void callback(EventMeshMessage eventMeshMessage, ChannelHandlerContext ctx) { - if (callback != null) { - callback.handle(eventMeshMessage).ifPresent( - responseMessage -> ctx.writeAndFlush(MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER))); - } - } - - @Override - public void response(Package tcpPackage) { - try { - send(tcpPackage); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - } -} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/gradle.properties b/eventmesh-storage-plugin/eventmesh-storage-kafka/gradle.properties index 84cc1ec8d2..67bd96bf26 100644 --- a/eventmesh-storage-plugin/eventmesh-storage-kafka/gradle.properties +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/gradle.properties @@ -14,7 +14,11 @@ # limitations under the License. # +<<<<<<<< HEAD:eventmesh-storage-plugin/eventmesh-storage-kafka/gradle.properties kafka_version=3.2.0 pluginType=storage -pluginName=kafka \ No newline at end of file +pluginName=kafka +======== +standalone=org.apache.eventmesh.connector.standalone.consumer.StandaloneConsumerAdaptor +>>>>>>>> 113b813a1 (Fix standalone connector interface, fix example (#608)):eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshMessageListenerConcurrently.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshMessageListenerConcurrently.java index 79ec322ad3..115ad20dc9 100644 --- a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshMessageListenerConcurrently.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshMessageListenerConcurrently.java @@ -15,7 +15,11 @@ * limitations under the License. */ +<<<<<<<< HEAD:eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshMessageListenerConcurrently.java package org.apache.eventmesh.storage.rocketmq.patch; +======== +package com.webank.runtime.patch; +>>>>>>>> 43bf39791 (event mesh project architecture adjustment):eventmesh-runtime/src/main/java/com/webank/runtime/patch/ProxyMessageListenerConcurrently.java import org.apache.commons.collections4.CollectionUtils; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; diff --git a/settings.gradle b/settings.gradle index b013a57929..ad6fc4ff39 100644 --- a/settings.gradle +++ b/settings.gradle @@ -120,6 +120,7 @@ include 'eventmesh-trace-plugin:eventmesh-trace-jaeger' include 'eventmesh-retry' include 'eventmesh-retry:eventmesh-retry-api' include 'eventmesh-retry:eventmesh-retry-rocketmq' +include 'eventmesh-retry:eventmesh-retry-kafka' include 'eventmesh-runtime-v2' include 'eventmesh-admin-server' include 'eventmesh-registry'