diff --git a/.gitignore b/.gitignore index e7ad09b..d4dd614 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ hs_err_pid* .idea *.iml -/target \ No newline at end of file +/*/target/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index d9b58da..9161855 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 yedf +Copyright (c) 2022 dtm-labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NewVersion.md b/NewVersion.md new file mode 100644 index 0000000..883524d --- /dev/null +++ b/NewVersion.md @@ -0,0 +1,17 @@ +# new version +新版本相比于旧版本Java client的的改造 +## 旧版本客户端 +![avatar](pic_ref/oldversion.png) +### 旧版本在设计上可以改进的一些地方 +1.引入的类从引入路径看不出来自哪个jar包,比如exception.FailureException。在大型项目中可能会出现多个相同的类名,如果不明确包名可能会导致意义混乱,甚至引入冲突。 +2.tcc等类直接依赖了dtmsvr信息,这样的依赖方式对后期的维护不友好,如果修改了DtmServerInfo的属性,那么后期需要修改所有支持的方式。应该做一个客户端这样的东西专门用来发送请求。 +3.向dtmsvr传递参数时使用了map来传递,虽然这对用户是无感知的,但是客户在debug的时候使用map比较麻烦,感觉使用一个param对象比较好 +## 新版本客户端 +![avatar](pic_ref/newversion.png) +### 新版本中改进的地方 +1.由于新版本需要同时支持http和feign两种交互方式,因此将请求dtmsvr相关的部分以及整个client的公共部分抽取出来形成了dtmcli-common模块,这样后续如果需要支持更多的交互方式只需要改动dtmcli-common中的代码,并在core新增代码 +2.springcloud版本的client不在乎需要传入ipport这样的配置参数,一切通过feign+nacos/euraka集成起来处理。因此将java-client和spring-client分开处理了 +3.对于一些非springcloud的项目我们也提供了java-client来处理,java-client支持像以前那样直接配置endpoint的方式,同时为了适配frontend服务,也支持通过配置nacos服务中心地址这样的方式来动态查找dtmsvr具体的地址。 +4.优化了整个项目的包结构,让引入dtmcli-java的时候能够快速找到来自哪个包 + + diff --git a/README.md b/README.md index 12ca8cb..277143b 100644 --- a/README.md +++ b/README.md @@ -45,29 +45,18 @@ DTM是一款跨语言的开源分布式事务管理器,优雅的解决了幂 ## 使用方式 -### 步骤一:JitPack 存储库添加到您的构建文件 - -Maven: - -```bash - - - jitpack.io - https://jitpack.io - - -``` - -Gradle: - -```bash -allprojects { - repositories { - ... - maven { url 'https://jitpack.io' } - } - } -``` +### 步骤一:确定你需要使用的版本 +1. 您的项目是springcloud项目 +- 您的项目中springboot版本>=2.4.0,请选择dtmcli-springcloud相应的版本直接接入即可 +- 您的项目中的springboot版本<2.4.0,请选择dtmcli-java接入,dtmcli-java也提供了微服务相关的接口,请设置nacos服务中心的相关配置即可使用 +2. 您的项目是普通项目/没有接入微服务的spring(boot)项目 +- 请选择dtmcli-java,并设置相应的配置即可 + +| artifact| version | 适用版本 |备注| +|:-----:|:----:|:----:|:----:| +|dtmcli-springcloud| 2.1.4.1| 2.4.0 <= springboot version < 2.5.13| springboot 版本>=2.5.0,需要设置spring.cloud.compatibility-verifier.enabled=false| +|dtmcli-springcloud| 2.1.4.2| 2.6.0 <= springboot version < 2.6.latest| | +|dtmcli-java| 2.1.4| others| | ### 步骤二:添加依赖项 @@ -75,9 +64,9 @@ Maven: ```bash - com.github.yedf - dtmcli-java - Tag + io.github.dtm-labs + dtmcli-springcloud + ${dtmcli.version} ``` @@ -85,10 +74,25 @@ Gradle: ```bash dependencies { - implementation 'com.github.yedf:dtmcli-java:Tag' + implementation 'io.github.dtm-labs:dtmcli-springcloud:${dtmcli.version}' } ``` +### 步骤三:设置dtmcli-java配置 +如果您引入了dtmcli-java,则需要新建一个`dtm-conf.properties`配置文件 +- 情形一:您引入了nacos等服务中心组件的配置文件 +``` +serverAddr=127.0.0.1:8848 +username=nacos +password=nacos +namespace=c3dc917d-906a-429d-90a9-85012b41014e +dtm.service.name=dtmService +dtm.service.registryType=nacos +``` +- 情形二:您直连dtmsvr +``` +dtm.ipport=127.0.0.1:36789 +``` ## 示例 ```bash @@ -125,10 +129,14 @@ dependencies { ### 完整示例 -[dtmcli-java-sample](https://github.com/dtm-labs/dtmcli-java-sample) +#### dtmcli-java使用示例 +[dtmcli-java-sample](https://github.com/dtm-labs/dtmcli-java-sample) +[dtmcli-java-sample-use-configuration](https://github.com/horseLk/dtmcli-java-sample-with-conf) +#### dtmcli-springcloud使用示例 +[dtmcli-java-spring-sample](https://github.com/dtm-labs/dtmcli-java-spring-sample) ### License [MIT](https://github.com/dtm-labs/dtmcli/blob/master/LICENSE) -[license-badge]: https://img.shields.io/github/license/dtm-labs/dtmcli-py \ No newline at end of file +[license-badge]: https://img.shields.io/github/license/dtm-labs/dtmcli-py diff --git a/dtmcli-common/pom.xml b/dtmcli-common/pom.xml new file mode 100644 index 0000000..8f58649 --- /dev/null +++ b/dtmcli-common/pom.xml @@ -0,0 +1,60 @@ + + + + dtmcli-java-parent + io.github.dtm-labs + 2.1.4 + + 4.0.0 + + dtmcli-common + 2.1.4 + jar + dtmcli-common + + + UTF-8 + 1.8 + 1.8 + + + + + + com.fasterxml.jackson.core + jackson-databind + + + + org.projectlombok + lombok + + + + io.github.openfeign + feign-core + + + + org.apache.commons + commons-lang3 + + + + com.squareup.okhttp3 + okhttp + + + + com.alibaba.nacos + nacos-client + + + + org.slf4j + slf4j-api + + + \ No newline at end of file diff --git a/dtmcli-common/src/main/java/pub/dtm/client/constant/Constants.java b/dtmcli-common/src/main/java/pub/dtm/client/constant/Constants.java new file mode 100644 index 0000000..a0fb213 --- /dev/null +++ b/dtmcli-common/src/main/java/pub/dtm/client/constant/Constants.java @@ -0,0 +1,66 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.constant; + +/** + * Constants + * + * @author horseLk + */ +public class Constants { + public static final String MICRO_SERVICE_NAME_KEY = "dtm.service.name"; + + public static final String GET_METHOD = "GET "; + + public static final String POST_METHOD = "POST "; + + public static final String HTTP_PREFIX = "http://"; + + public static final String HTTPS_PREFIX = "https://"; + + public static final String PING_URL = "/api/ping"; + + private static final String BASE_URL = "/api/dtmsvr"; + + public static final String NEW_GID_URL = BASE_URL + "/newGid"; + + public static final String PREPARE_URL = BASE_URL + "/prepare"; + + public static final String SUBMIT_URL = BASE_URL + "/submit"; + + public static final String ABORT_URL = BASE_URL + "/abort"; + + public static final String REGISTER_BRANCH_URL = BASE_URL + "/registerBranch"; + + public static final String DEFAULT_STATUS = "prepared"; + + public static final String EMPTY_STRING = ""; + + public static final String SUCCESS_RESULT = "SUCCESS"; + + public static final String FAILURE_RESULT = "FAILURE"; + + public static final int RESP_ERR_CODE = 400; +} diff --git a/src/main/java/common/constant/ParamFieldConstant.java b/dtmcli-common/src/main/java/pub/dtm/client/constant/ParamFieldConstants.java similarity index 93% rename from src/main/java/common/constant/ParamFieldConstant.java rename to dtmcli-common/src/main/java/pub/dtm/client/constant/ParamFieldConstants.java index 3da26d0..0a38075 100644 --- a/src/main/java/common/constant/ParamFieldConstant.java +++ b/dtmcli-common/src/main/java/pub/dtm/client/constant/ParamFieldConstants.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,13 +22,14 @@ * SOFTWARE. */ -package common.constant; +package pub.dtm.client.constant; /** - * @author lixiaoshuang + * Constants for dtm server parameter key + * + * @author horseLk */ -public class ParamFieldConstant { - +public class ParamFieldConstants { public static final String GID = "gid"; public static final String TRANS_TYPE = "trans_type"; @@ -72,5 +73,4 @@ public class ParamFieldConstant { public static final String PASSTHROGH_HEADERS = "passthrough_headers"; public static final String BRANCH_HEADERS = "branch_headers"; - } diff --git a/src/main/java/common/model/TransBase.java b/dtmcli-common/src/main/java/pub/dtm/client/enums/TransTypeEnum.java similarity index 56% rename from src/main/java/common/model/TransBase.java rename to dtmcli-common/src/main/java/pub/dtm/client/enums/TransTypeEnum.java index 9d3ecdf..21d881b 100644 --- a/src/main/java/common/model/TransBase.java +++ b/dtmcli-common/src/main/java/pub/dtm/client/enums/TransTypeEnum.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,49 +22,57 @@ * SOFTWARE. */ -package common.model; +package pub.dtm.client.enums; -import common.enums.TransTypeEnum; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -@Data -@NoArgsConstructor -public class TransBase { - +/** + * Transtype enum + * + * @author horseLk + */ +public enum TransTypeEnum { /** - * 全局事务id + * tcc */ - private String gid; - + TCC("tcc"), /** - * 事务类型 + * xa */ - private TransTypeEnum transTypeEnum; - - private boolean waitResult; - - private long timeoutToFail; - - private long retryInterval; + XA("xa"), + /** + * msg + */ + MSG("msg"), + /** + * saga + */ + SAGA("saga") + ; - private Map branchHeaders = new HashMap<>(); + TransTypeEnum(String value) { + this.value = value; + } - private ArrayList passthroughHeaders = new ArrayList<>(); + /** + * Trans type string + */ + private final String value; - private String customData; + public String getValue() { + return this.value; + } - private ArrayList> steps = new ArrayList<>(); + private static final Map EXIST = new HashMap<>(); - private ArrayList payloads = new ArrayList<>(); + static { + for (TransTypeEnum transType : TransTypeEnum.values()) { + EXIST.put(transType.value, transType); + } + } - public TransBase(TransTypeEnum transTypeEnum, String gid, boolean waitResult) { - this.gid = gid; - this.transTypeEnum = transTypeEnum; - this.waitResult = waitResult; + public static TransTypeEnum parseString(String value) { + return EXIST.get(value); } -} \ No newline at end of file +} diff --git a/src/main/java/exception/FailureException.java b/dtmcli-common/src/main/java/pub/dtm/client/exception/FailureException.java similarity index 82% rename from src/main/java/exception/FailureException.java rename to dtmcli-common/src/main/java/pub/dtm/client/exception/FailureException.java index 768dc9d..c5dc22a 100644 --- a/src/main/java/exception/FailureException.java +++ b/dtmcli-common/src/main/java/pub/dtm/client/exception/FailureException.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,11 +22,19 @@ * SOFTWARE. */ -package exception; +package pub.dtm.client.exception; +/** + * dtm common exception + * + * @author horseLk + */ public class FailureException extends Exception { - - public FailureException(String message) { - super(message); + public FailureException(String msg) { + super(msg); + } + + public FailureException(Throwable e) { + super(e); } } diff --git a/src/main/java/common/model/DtmConsumer.java b/dtmcli-common/src/main/java/pub/dtm/client/interfaces/dtm/DtmConsumer.java similarity index 81% rename from src/main/java/common/model/DtmConsumer.java rename to dtmcli-common/src/main/java/pub/dtm/client/interfaces/dtm/DtmConsumer.java index 2b5ffdb..0d7034e 100644 --- a/src/main/java/common/model/DtmConsumer.java +++ b/dtmcli-common/src/main/java/pub/dtm/client/interfaces/dtm/DtmConsumer.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,13 +22,17 @@ * SOFTWARE. */ -package common.model; +package pub.dtm.client.interfaces.dtm; + +import pub.dtm.client.model.dtm.TransBase; /** - * @author lixiaoshuang + * Functional Interface for Transtype to process busi request + * + * @param + * @author horseLk */ @FunctionalInterface -public interface DtmConsumer { - +public interface DtmConsumer { void accept(T t) throws Exception; } diff --git a/dtmcli-common/src/main/java/pub/dtm/client/interfaces/stub/IDtmServerStub.java b/dtmcli-common/src/main/java/pub/dtm/client/interfaces/stub/IDtmServerStub.java new file mode 100644 index 0000000..8d9cd64 --- /dev/null +++ b/dtmcli-common/src/main/java/pub/dtm/client/interfaces/stub/IDtmServerStub.java @@ -0,0 +1,96 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.interfaces.stub; + +import feign.Response; +import pub.dtm.client.model.param.OperatorParam; +import pub.dtm.client.model.responses.DtmResponse; + +import java.net.URI; +import java.util.Map; + +/** + * A stub interface for dtm svr, different client has different implements. + * + * @author horseLk + */ +public interface IDtmServerStub { + /** + * get stubType + * @return type + */ + String stubType(); + + /** + * get a new gid + */ + DtmResponse newGid(); + + /** + * test connection + */ + DtmResponse ping(); + + /** + * prepare + * @param body prepare body + */ + DtmResponse prepare(OperatorParam body); + + /** + * submit + * @param body submit bosy + */ + DtmResponse submit(OperatorParam body); + + /** + * abort + * @param body abort body + */ + DtmResponse abort(OperatorParam body); + + /** + * registerBranch + * @param body registerBranch body + */ + DtmResponse registerBranch(OperatorParam body); + + /** + * use feign send busi get request + * @param host busi host + * @param path busi path + * @param queryMap querymao + */ + Response busiGet(URI host, String path, Map queryMap); + + /** + * use feign send busi post request + * @param host busi host + * @param path busi path + * @param queryMap query map + * @param body request body + */ + Response busiPost(URI host, String path, Map queryMap, Object body); +} diff --git a/src/main/java/common/constant/Constant.java b/dtmcli-common/src/main/java/pub/dtm/client/interfaces/stub/IURIParser.java similarity index 67% rename from src/main/java/common/constant/Constant.java rename to dtmcli-common/src/main/java/pub/dtm/client/interfaces/stub/IURIParser.java index c90a7de..3a77e8b 100644 --- a/src/main/java/common/constant/Constant.java +++ b/dtmcli-common/src/main/java/pub/dtm/client/interfaces/stub/IURIParser.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,17 +22,22 @@ * SOFTWARE. */ -package common.constant; +package pub.dtm.client.interfaces.stub; + +import pub.dtm.client.model.feign.ServiceMessage; /** - * @author lixiaoshuang + * URI Parser interface + * + * @author horseLk */ -public class Constant { - - public static final int DEFAULT_INITIAL_CAPACITY = 16; - - public static final String SUCCESS_RESULT = "SUCCESS"; - - public static final String FAILURE_RESULT = "FAILURE"; - +public interface IURIParser { + /** + * according to serviceMessage and connection driver generate uri + * @param serviceMessage service message + * @param httpType true means http, false means microservice + * @return uri + * @throws Exception exception + */ + String generatorURI(ServiceMessage serviceMessage, boolean httpType) throws Exception; } diff --git a/src/main/java/common/utils/StreamUtil.java b/dtmcli-common/src/main/java/pub/dtm/client/log/DtmFeignLogger.java similarity index 52% rename from src/main/java/common/utils/StreamUtil.java rename to dtmcli-common/src/main/java/pub/dtm/client/log/DtmFeignLogger.java index 0d1af20..ebd1d7c 100644 --- a/src/main/java/common/utils/StreamUtil.java +++ b/dtmcli-common/src/main/java/pub/dtm/client/log/DtmFeignLogger.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,42 +22,42 @@ * SOFTWARE. */ -package common.utils; +package pub.dtm.client.log; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * @author lixiaoshuang + * Custom feign logger for print detail feign log + * + * @author horseLk */ -public class StreamUtil { - - public static byte[] copyToByteArray(InputStream in) throws IOException { - if (in == null) { - return new byte[0]; - } else { - ByteArrayOutputStream out = new ByteArrayOutputStream(4096); - copy(in, out); - return out.toByteArray(); - } +public class DtmFeignLogger extends feign.Logger { + private final Logger logger; + + public DtmFeignLogger() { + this(feign.Logger.class); } - - private static int copy(InputStream in, OutputStream out) throws IOException { - int byteCount = 0; - if (null == in) { - return byteCount; - } - if (null == out) { - return byteCount; - } - int bytesRead; - for (byte[] buffer = new byte[4096]; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) { - out.write(buffer, 0, bytesRead); + + public DtmFeignLogger(Class clazz) { + this(LoggerFactory.getLogger(clazz)); + } + + public DtmFeignLogger(String name) { + this(LoggerFactory.getLogger(name)); + } + + DtmFeignLogger(Logger logger) { + this.logger = logger; + } + + @Override + protected void log(String configKey, String format, Object... args) { + // Not using SLF4J's support for parameterized messages (even though it + // would be more efficient) because it would + // require the incoming message formats to be SLF4J-specific. + if (logger.isInfoEnabled()) { + logger.info(String.format(methodTag(configKey) + format, args)); } - out.flush(); - return byteCount; } - } diff --git a/src/main/java/common/enums/TransTypeEnum.java b/dtmcli-common/src/main/java/pub/dtm/client/model/dtm/TransBase.java similarity index 66% rename from src/main/java/common/enums/TransTypeEnum.java rename to dtmcli-common/src/main/java/pub/dtm/client/model/dtm/TransBase.java index 7336c41..89c5397 100644 --- a/src/main/java/common/enums/TransTypeEnum.java +++ b/dtmcli-common/src/main/java/pub/dtm/client/model/dtm/TransBase.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,20 +22,34 @@ * SOFTWARE. */ -package common.enums; +package pub.dtm.client.model.dtm; -public enum TransTypeEnum { - // 事务类型 - TCC("tcc"), SAGA("saga"); +import pub.dtm.client.enums.TransTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; - TransTypeEnum(String value) { - this.value = value; - } - - private String value; +/** + * base Class for different Trans type + * + * @author horseLk + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TransBase { + /** + * global transaction id + */ + private String gid; - public String getValue() { - return this.value; - } + /** + * trans type + */ + private TransTypeEnum transTypeEnum; -} \ No newline at end of file + /** + * is wait for result + */ + private boolean waitResult; +} diff --git a/dtmcli-common/src/main/java/pub/dtm/client/model/feign/ServiceMessage.java b/dtmcli-common/src/main/java/pub/dtm/client/model/feign/ServiceMessage.java new file mode 100644 index 0000000..4d570be --- /dev/null +++ b/dtmcli-common/src/main/java/pub/dtm/client/model/feign/ServiceMessage.java @@ -0,0 +1,89 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.model.feign; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Service message for micro service + * + * @author horseLk + */ +@Data +@NoArgsConstructor +public class ServiceMessage { + /** + * service name + */ + private String serviceName; + + /** + * group name + */ + private String groupName = "DEFAULT_GROUP"; + + /** + * clusters + */ + private List cluster = new ArrayList<>(); + + /** + * request path + */ + private String path; + + public ServiceMessage(String serviceName, String path){ + this.serviceName = serviceName; + this.path = path; + } + + public ServiceMessage(String serviceName, String groupName, List cluster, String path) { + this.serviceName = serviceName; + this.groupName = groupName; + this.cluster.addAll(cluster); + this.path = path; + } + + public String getPath() { + if (StringUtils.startsWith(path, "/")) { + return path; + } + return "/" + path; + } + + @Override + public String toString() { + String _path = path; + if (!StringUtils.startsWith(path, "/")) { + _path = "/" + path; + } + return serviceName + _path + "?groupName=" + groupName; + } +} diff --git a/dtmcli-common/src/main/java/pub/dtm/client/model/param/OperatorParam.java b/dtmcli-common/src/main/java/pub/dtm/client/model/param/OperatorParam.java new file mode 100644 index 0000000..efa334d --- /dev/null +++ b/dtmcli-common/src/main/java/pub/dtm/client/model/param/OperatorParam.java @@ -0,0 +1,72 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.model.param; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import pub.dtm.client.constant.ParamFieldConstants; +import pub.dtm.client.enums.TransTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Request Param for dtm svr + * + * @author horseLk + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "subType") +@JsonSubTypes({ + @JsonSubTypes.Type(value = TccOperatorParam.class, name = "tcc"), + @JsonSubTypes.Type(value = SagaOperatorParam.class, name = "saga") +}) +public class OperatorParam { + /** + * gid + */ + @JsonProperty(ParamFieldConstants.GID) + private String gid; + + /** + * trans type string value + */ + @JsonProperty(ParamFieldConstants.TRANS_TYPE) + private String transType; + + /** + * this attribute just for mark different sub class for encode/decode. + */ + @JsonProperty("subType") + private String subType; + + public OperatorParam(String gid, TransTypeEnum transType) { + this.gid = gid; + this.transType = transType.getValue(); + } +} diff --git a/dtmcli-common/src/main/java/pub/dtm/client/model/param/SagaOperatorParam.java b/dtmcli-common/src/main/java/pub/dtm/client/model/param/SagaOperatorParam.java new file mode 100644 index 0000000..cbe06ae --- /dev/null +++ b/dtmcli-common/src/main/java/pub/dtm/client/model/param/SagaOperatorParam.java @@ -0,0 +1,82 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.model.param; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.NoArgsConstructor; +import pub.dtm.client.constant.ParamFieldConstants; +import pub.dtm.client.enums.TransTypeEnum; + +import java.util.List; +import java.util.Map; + +/** + * Saga Operator Param + * + * @author horseLk + */ +@Data +@NoArgsConstructor +public class SagaOperatorParam extends OperatorParam { + @JsonProperty(ParamFieldConstants.STEPS) + private List> steps; + + @JsonProperty(ParamFieldConstants.PAYLOADS) + private List payloads; + + @JsonProperty(ParamFieldConstants.CUSTOM_DATA) + private String customData; + + @JsonProperty(ParamFieldConstants.WAIT_RESULT) + private boolean waitResult; + + @JsonProperty(ParamFieldConstants.TIMEOUT_TO_FAIL) + private long timeoutToFail; + + @JsonProperty(ParamFieldConstants.RETRY_INTERVAL) + private long retryInterval; + + @JsonProperty(ParamFieldConstants.PASSTHROGH_HEADERS) + private List passthroughHeaders; + + @JsonProperty(ParamFieldConstants.BRANCH_HEADERS) + private Map branchHeaders; + + public SagaOperatorParam(String gid, TransTypeEnum transType, List> steps, + List payloads, String customData, boolean waitResult, long timeoutToFail, + long retryInterval, List passthroughHeaders, Map branchHeaders) { + super(gid, transType); + setSubType(transType.getValue()); + this.steps = steps; + this.payloads = payloads; + this.customData = customData; + this.waitResult = waitResult; + this.timeoutToFail = timeoutToFail; + this.retryInterval = retryInterval; + this.passthroughHeaders = passthroughHeaders; + this.branchHeaders = branchHeaders; + } +} diff --git a/dtmcli-common/src/main/java/pub/dtm/client/model/param/TccOperatorParam.java b/dtmcli-common/src/main/java/pub/dtm/client/model/param/TccOperatorParam.java new file mode 100644 index 0000000..11d3b6c --- /dev/null +++ b/dtmcli-common/src/main/java/pub/dtm/client/model/param/TccOperatorParam.java @@ -0,0 +1,81 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.model.param; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.NoArgsConstructor; +import pub.dtm.client.constant.ParamFieldConstants; +import pub.dtm.client.enums.TransTypeEnum; + +/** + * Tcc Operator Param + * @author horseLk + */ +@Data +@NoArgsConstructor +public class TccOperatorParam extends OperatorParam { + /** + * branch id + */ + @JsonProperty(ParamFieldConstants.BRANCH_ID) + private String branchId; + + /** + * status + */ + @JsonProperty(ParamFieldConstants.STATUS) + private String status; + + /** + * data + */ + @JsonProperty(ParamFieldConstants.DATA) + private String data; + + /** + * branch confirm uri + */ + @JsonProperty(ParamFieldConstants.CONFIRM) + private String confirm; + + /** + * branch cancel uri + */ + @JsonProperty(ParamFieldConstants.CANCEL) + private String cancel; + + + public TccOperatorParam(String gid, TransTypeEnum transTypeEnum, String branchId, String status, String data, + String confirm, String cancel) { + super(gid, transTypeEnum); + setSubType(transTypeEnum.getValue()); + this.branchId = branchId; + this.status = status; + this.data = data; + this.confirm = confirm; + this.cancel = cancel; + } +} diff --git a/dtmcli-common/src/main/java/pub/dtm/client/model/responses/DtmResponse.java b/dtmcli-common/src/main/java/pub/dtm/client/model/responses/DtmResponse.java new file mode 100644 index 0000000..799a8ad --- /dev/null +++ b/dtmcli-common/src/main/java/pub/dtm/client/model/responses/DtmResponse.java @@ -0,0 +1,56 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.model.responses; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Response from dtm svr + * + * @author horseLk + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DtmResponse { + /** + * dtm_result + */ + @JsonProperty("dtm_result") + private String dtmResult; + + /** + * gid + */ + @JsonProperty("gid") + private String gid; + + public static DtmResponse buildDtmResponse(String result) { + return new DtmResponse(result, null); + } +} diff --git a/dtmcli-common/src/main/java/pub/dtm/client/utils/FeignUtils.java b/dtmcli-common/src/main/java/pub/dtm/client/utils/FeignUtils.java new file mode 100644 index 0000000..45a9544 --- /dev/null +++ b/dtmcli-common/src/main/java/pub/dtm/client/utils/FeignUtils.java @@ -0,0 +1,119 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.utils; + +import pub.dtm.client.constant.Constants; +import pub.dtm.client.exception.FailureException; +import feign.Response; +import pub.dtm.client.interfaces.stub.IURIParser; +import pub.dtm.client.model.feign.ServiceMessage; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import pub.dtm.client.model.responses.DtmResponse; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +/** + * Feign Utils + * + * @author horseLk + */ +public class FeignUtils { + /** + * log + */ + private static final Logger log = LoggerFactory.getLogger(FeignUtils.class); + + /** + * URIParser + */ + private static IURIParser uriParser; + + public static void setUriParser(IURIParser uriParser) { + FeignUtils.uriParser = uriParser; + } + + /** + * Get gid from DtmResponse + * @param base dtmResponse + * @return gid + * @throws Exception exception + */ + public static String parseGid(DtmResponse base) throws Exception { + if (base == null || !Constants.SUCCESS_RESULT.equals(base.getDtmResult())) { + throw new Exception("get new gid from dtm server fail."); + } + return base.getGid(); + } + + /** + * generate uri + * @param serviceMessage service message + * @param httpType true means http, false means micro service + * @return uri + * @throws Exception exception + */ + public static String generatorURI(ServiceMessage serviceMessage, boolean httpType) throws Exception { + return uriParser.generatorURI(serviceMessage, httpType); + } + + /** + * check response + * @param response feign response + * @throws FailureException exception + */ + public static void checkResult(Response response) throws FailureException { + if (response.status() >= Constants.RESP_ERR_CODE){ + if (response.reason() != null) { + throw new FailureException(response.reason()); + } + try { + log.error("response code is {}, but unknown reason, response body is {}", response.status(), + IOUtils.toString(response.body().asReader(StandardCharsets.UTF_8))); + } finally { + throw new FailureException("response code is " + response.status()); + } + } + String result = ""; + try { + InputStream inputStream = response.body().asInputStream(); + if (inputStream != null) { + result = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + } + } catch (IOException e) { + throw new FailureException("response is null"); + } + if (StringUtils.isBlank(result)) { + throw new FailureException("response is null"); + } + if (result.contains(Constants.FAILURE_RESULT)){ + throw new FailureException("Service returned failed"); + } + } +} diff --git a/dtmcli-common/src/main/java/pub/dtm/client/utils/HttpUtils.java b/dtmcli-common/src/main/java/pub/dtm/client/utils/HttpUtils.java new file mode 100644 index 0000000..94a9e68 --- /dev/null +++ b/dtmcli-common/src/main/java/pub/dtm/client/utils/HttpUtils.java @@ -0,0 +1,123 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.utils; + +import pub.dtm.client.constant.Constants; +import pub.dtm.client.exception.FailureException; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * Http utils + * + * @author horseLk + */ +public class HttpUtils { + private static final OkHttpClient CLIENT = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS) + .readTimeout(5, TimeUnit.SECONDS).writeTimeout(5, TimeUnit.SECONDS).build(); + + public static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=utf-8"); + + /** + * send get request + * @param url url + * @return http response + * @throws IOException exception + */ + public static Response get(String url) throws IOException { + Request request = new Request.Builder().url(url).get().build(); + return CLIENT.newCall(request).execute(); + } + + /** + * send post request + * @param url url + * @param json body json + * @return http response + * @throws IOException exception + */ + public static Response post(String url, String json) throws IOException { + RequestBody body = RequestBody.create(MEDIA_TYPE, json); + Request request = new Request.Builder().url(url).post(body).build(); + return CLIENT.newCall(request).execute(); + } + + /** + * splice url with query map + * @param url main url + * @param params query map + * @return string + */ + public static String splicingUrl(String url, Map params) { + if (params == null || params.isEmpty()) { + return url; + } + StringBuilder builder = new StringBuilder(url).append("?"); + for (Map.Entry entry : params.entrySet()) { + builder.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); + } + return builder.deleteCharAt(builder.length() - 1).toString(); + } + + + /** + * splice url without query map + * @param ip ip + * @param port port + * @param path path + * @return string + */ + public static String splicingUrl(String ip, int port, String path) { + return Constants.HTTP_PREFIX + ip + ":" + String.valueOf(port) + path; + } + + /** + * check response + * @param response http response + * @throws Exception exception + */ + public static void checkResult(Response response) throws Exception { + if (response.code() >= Constants.RESP_ERR_CODE){ + throw new FailureException(response.message()); + } + ResponseBody body = response.body(); + String result; + if (body == null || StringUtils.isBlank(result = body.string())) { + throw new FailureException("response is null"); + } + if (result.contains(Constants.FAILURE_RESULT)){ + throw new FailureException("Service returned failed"); + } + } +} diff --git a/dtmcli-common/src/main/java/pub/dtm/client/utils/JsonUtils.java b/dtmcli-common/src/main/java/pub/dtm/client/utils/JsonUtils.java new file mode 100644 index 0000000..9bf435b --- /dev/null +++ b/dtmcli-common/src/main/java/pub/dtm/client/utils/JsonUtils.java @@ -0,0 +1,51 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; + +/** + * Json Utils + * + * @author horseLk + */ +public class JsonUtils { + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public static T parseJson(String json, Class clzz) throws JsonProcessingException { + return objectMapper.readValue(json, clzz); + } + + public static T parseJson(byte[] bytes, Class clzz) throws IOException { + return objectMapper.readValue(bytes, clzz); + } + + public static String toJson(Object object) throws JsonProcessingException { + return objectMapper.writeValueAsString(object); + } +} diff --git a/dtmcli-core/pom.xml b/dtmcli-core/pom.xml new file mode 100644 index 0000000..574fb5c --- /dev/null +++ b/dtmcli-core/pom.xml @@ -0,0 +1,42 @@ + + + + dtmcli-java-parent + io.github.dtm-labs + 2.1.4 + + 4.0.0 + + dtmcli-core + 2.1.4 + jar + dtmcli-core + + + UTF-8 + 1.8 + 1.8 + + + + + io.github.dtm-labs + dtmcli-common + 2.1.4 + + + + org.apache.commons + commons-lang3 + + + + org.slf4j + slf4j-api + + + + + \ No newline at end of file diff --git a/src/main/java/barrier/BarrierParam.java b/dtmcli-core/src/main/java/pub/dtm/client/barrier/BarrierParam.java similarity index 82% rename from src/main/java/barrier/BarrierParam.java rename to dtmcli-core/src/main/java/pub/dtm/client/barrier/BarrierParam.java index 35c1de4..2af09f2 100644 --- a/src/main/java/barrier/BarrierParam.java +++ b/dtmcli-core/src/main/java/pub/dtm/client/barrier/BarrierParam.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,36 +22,38 @@ * SOFTWARE. */ -package barrier; +package pub.dtm.client.barrier; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; /** - * dtm 服务端传过来的字段格式为下划线分隔,为了减少sdk对json包依赖也采用下划线格式 + * Branch barrier parameter * - * @author lixiaoshuang + * @author horseLk */ @Data +@NoArgsConstructor +@AllArgsConstructor public class BarrierParam { - /** - * 事务类型 + * trans type */ private String trans_type[]; - + /** - * 全局事务id + * gid */ private String gid[]; - + /** - * 分支id + * branch id */ private String branch_id[]; - + /** - * 操作 + * operator */ private String op[]; - } diff --git a/src/main/java/barrier/BranchBarrier.java b/dtmcli-core/src/main/java/pub/dtm/client/barrier/BranchBarrier.java similarity index 64% rename from src/main/java/barrier/BranchBarrier.java rename to dtmcli-core/src/main/java/pub/dtm/client/barrier/BranchBarrier.java index 7604306..05ed66c 100644 --- a/src/main/java/barrier/BranchBarrier.java +++ b/dtmcli-core/src/main/java/pub/dtm/client/barrier/BranchBarrier.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,14 +22,19 @@ * SOFTWARE. */ -package barrier; +package pub.dtm.client.barrier; -import com.alibaba.fastjson.JSONObject; -import common.constant.ParamFieldConstant; -import common.model.DtmConsumer; +import pub.dtm.client.constant.ParamFieldConstants; +import pub.dtm.client.enums.TransTypeEnum; +import pub.dtm.client.exception.FailureException; +import pub.dtm.client.interfaces.dtm.DtmConsumer; import lombok.Data; import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import pub.dtm.client.model.dtm.TransBase; +import org.apache.commons.lang3.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import pub.dtm.client.utils.JsonUtils; import java.sql.Connection; import java.sql.PreparedStatement; @@ -38,68 +43,57 @@ import java.util.Objects; /** - * @author lixiaoshuang + * Branch barrier service + * + * @author horseLk */ @Data @NoArgsConstructor -@Slf4j -public class BranchBarrier { - - /** - * 事务类型 - */ - private String transType; - - /** - * 全局事务id - */ - private String gid; - +public class BranchBarrier extends TransBase { + private static final Logger log = LoggerFactory.getLogger(BranchBarrier.class); + /** - * 分支id + * branch id */ private String branchId; - + /** - * 操作 + * operator */ private String op; - + /** - * 屏障id + * barrier id */ private int barrierId; - - - public BranchBarrier(Map parameterMap) throws Exception { - if (null == parameterMap) { - throw new Exception("BranchBarrier parameterMap null!"); + + public BranchBarrier(Map paramsMap) throws Exception { + if (paramsMap == null || paramsMap.isEmpty()) { + throw new FailureException("build BranchBarrier error, paramsMap can not be empty."); } - BarrierParam barrierParam = JSONObject.parseObject(JSONObject.toJSONString(parameterMap), BarrierParam.class); - if (barrierParam.getTrans_type().length > 0) { - this.transType = barrierParam.getTrans_type()[0]; + BarrierParam barrierParam = JsonUtils.parseJson(JsonUtils.toJson(paramsMap), BarrierParam.class); + if (ArrayUtils.isNotEmpty(barrierParam.getTrans_type())) { + this.setTransTypeEnum(TransTypeEnum.parseString(barrierParam.getTrans_type()[0])); } - if (barrierParam.getGid().length > 0) { - this.gid = barrierParam.getGid()[0]; + if (ArrayUtils.isNotEmpty(barrierParam.getGid())) { + this.setGid(barrierParam.getGid()[0]); } - if (barrierParam.getBranch_id().length > 0) { + if (ArrayUtils.isNotEmpty(barrierParam.getBranch_id())) { this.branchId = barrierParam.getBranch_id()[0]; } - if (barrierParam.getOp().length > 0) { + if (ArrayUtils.isNotEmpty(barrierParam.getOp())) { this.op = barrierParam.getOp()[0]; } } - + /** - * connection 由使用方自行管理,创建、回收。 - * - * @param connection - * @param consumer - * @return - * @throws SQLException + * Busi can call method call() to open branch barrier + * @param connection data source connection + * @param consumer consumer + * @throws Exception exception */ public void call(Connection connection, DtmConsumer consumer) throws Exception { - this.barrierId++; + ++this.barrierId; connection.setAutoCommit(false); try { boolean result = insertBarrier(connection); @@ -115,8 +109,9 @@ public void call(Connection connection, DtmConsumer consumer) thr connection.setAutoCommit(true); } } - + private boolean insertBarrier(Connection connection) throws SQLException { + log.info("insert barrier {}", this); if (Objects.isNull(connection)) { return false; } @@ -124,19 +119,19 @@ private boolean insertBarrier(Connection connection) throws SQLException { try { String sql = "insert ignore into barrier(trans_type, gid, branch_id, op, barrier_id, reason) values(?,?,?,?,?,?)"; preparedStatement = connection.prepareStatement(sql); - preparedStatement.setString(1, transType); - preparedStatement.setString(2, gid); + preparedStatement.setString(1, this.getTransTypeEnum().getValue()); + preparedStatement.setString(2, this.getGid()); preparedStatement.setString(3, branchId); preparedStatement.setString(4, op); preparedStatement.setString(5, String.format("%02d", barrierId)); preparedStatement.setString(6, op); - + if (preparedStatement.executeUpdate() == 0) { return false; } - if (op.equals(ParamFieldConstant.CANCEL)) { + if (ParamFieldConstants.CANCEL.equals(op)) { int opIndex = 4; - preparedStatement.setString(opIndex, ParamFieldConstant.TRY); + preparedStatement.setString(opIndex, ParamFieldConstants.TRY); if (preparedStatement.executeUpdate() > 0) { return false; } @@ -148,4 +143,5 @@ private boolean insertBarrier(Connection connection) throws SQLException { } return true; } + } diff --git a/src/main/java/common/utils/BranchIdGeneratorUtil.java b/dtmcli-core/src/main/java/pub/dtm/client/base/BranchIdGenerator.java similarity index 80% rename from src/main/java/common/utils/BranchIdGeneratorUtil.java rename to dtmcli-core/src/main/java/pub/dtm/client/base/BranchIdGenerator.java index a7fad79..3725ab3 100644 --- a/src/main/java/common/utils/BranchIdGeneratorUtil.java +++ b/dtmcli-core/src/main/java/pub/dtm/client/base/BranchIdGenerator.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,33 +22,37 @@ * SOFTWARE. */ -package common.utils; - -import lombok.Data; +package pub.dtm.client.base; /** - * @author lixiaoshuang + * BranchIdGenerator for generate branch id + * + * @author horseLk */ -@Data -public class BranchIdGeneratorUtil { - +public class BranchIdGenerator { private static final int MAX_BRANCH_ID = 99; private static final int LENGTH = 20; - private String branchId; + /** + * branch id prefix + */ + private final String branchId; + /** + * last branch id + */ private int subBranchId; - public BranchIdGeneratorUtil(String branchId) { + public BranchIdGenerator(String branchId) { this.branchId = branchId; } /** - * 生成注册分支id + * generate branch id * - * @return - * @throws Exception + * @return branch id + * @throws Exception exception */ public String genBranchId() throws Exception { if (this.subBranchId >= MAX_BRANCH_ID) { @@ -60,4 +64,4 @@ public String genBranchId() throws Exception { this.subBranchId++; return this.branchId + String.format("%02d", this.subBranchId); } -} \ No newline at end of file +} diff --git a/dtmcli-core/src/main/java/pub/dtm/client/saga/Saga.java b/dtmcli-core/src/main/java/pub/dtm/client/saga/Saga.java new file mode 100644 index 0000000..e23bde1 --- /dev/null +++ b/dtmcli-core/src/main/java/pub/dtm/client/saga/Saga.java @@ -0,0 +1,180 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.saga; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import pub.dtm.client.constant.ParamFieldConstants; +import pub.dtm.client.enums.TransTypeEnum; +import pub.dtm.client.exception.FailureException; +import pub.dtm.client.interfaces.stub.IDtmServerStub; +import pub.dtm.client.model.dtm.TransBase; +import pub.dtm.client.model.feign.ServiceMessage; +import pub.dtm.client.model.param.SagaOperatorParam; +import pub.dtm.client.utils.FeignUtils; +import pub.dtm.client.utils.JsonUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Saga trans type service + * + * @author horseLk + */ +@Data +@NoArgsConstructor +public class Saga extends TransBase { + private static final Logger log = LoggerFactory.getLogger(Saga.class); + + private static final String ORDERS = "orders"; + + private static final String CONCURRENT = "concurrent"; + + private IDtmServerStub dtmServerStub; + + private boolean concurrent; + + private Map> orders; + + private long timeoutToFail; + + private long retryInterval; + + private Map branchHeaders = new HashMap<>(); + + private List passthroughHeaders = new ArrayList<>(); + + private String customData; + + private List> steps = new ArrayList<>(); + + private List payloads = new ArrayList<>(); + + public Saga(String gid, IDtmServerStub dtmServerStub) { + super(gid, TransTypeEnum.SAGA, false); + this.concurrent = false; + this.orders = new HashMap<>(); + this.dtmServerStub = dtmServerStub; + } + + public Saga add(ServiceMessage action, ServiceMessage compensate, Object postData) { + Map step = new HashMap<>(); + try { + step.put(ParamFieldConstants.ACTION, FeignUtils.generatorURI(action, false)); + step.put(ParamFieldConstants.COMPENSATE, FeignUtils.generatorURI(compensate, false)); + this.payloads.add(JsonUtils.toJson(postData)); + } catch (Exception e) { + log.error("saga add branch error."); + } + this.steps.add(step); + + return this; + } + + public Saga add(String action, String compensate, Object postData) { + Map step = new HashMap<>(); + step.put(ParamFieldConstants.ACTION, action); + step.put(ParamFieldConstants.COMPENSATE, compensate); + this.steps.add(step); + try { + this.payloads.add(JsonUtils.toJson(postData)); + } catch (Exception e) { + log.error("encode json error."); + } + return this; + } + + public String submit() throws Exception { + if (StringUtils.isEmpty(this.getGid())) { + this.setGid(FeignUtils.parseGid(dtmServerStub.newGid())); + } + addConcurrentContext(); + SagaOperatorParam operatorParam = new SagaOperatorParam(this.getGid(), TransTypeEnum.SAGA, this.getSteps(), + this.getPayloads(), this.getCustomData(), this.isWaitResult(), this.getTimeoutToFail(), + this.getRetryInterval(), this.getPassthroughHeaders(), this.getBranchHeaders()); + + try { + dtmServerStub.submit(operatorParam); + } catch (Exception e) { + log.error("saga transaction submit failed, transaction gid is {}", this.getGid()); + throw new FailureException(e); + } + return this.getGid(); + } + + public Saga addBranchOrder(Integer branch, List preBranches) { + orders.put(branch.toString(), preBranches); + return this; + } + + public Saga enableConcurrent() { + concurrent = true; + return this; + } + + public Saga enableWaitResult() { + this.setWaitResult(true); + return this; + } + + public Saga setTimeoutToFail(long timeoutToFail) { + this.setTimeoutToFail(timeoutToFail); + return this; + } + + public Saga setRetryInterval(long retryInterval) { + this.setRetryInterval(retryInterval); + return this; + } + + public Saga setBranchHeaders(Map headers) { + this.setBranchHeaders(headers); + return this; + } + + public Saga setPassthroughHeaders(ArrayList passthroughHeaders) { + this.setPassthroughHeaders(passthroughHeaders); + return this; + } + + private void addConcurrentContext() { + if (concurrent) { + HashMap data = new HashMap<>(); + data.put(ORDERS, orders); + data.put(CONCURRENT, true); + try { + this.setCustomData(JsonUtils.toJson(data)); + } catch (Exception e) { + log.error("encode json error."); + } + } + } +} diff --git a/dtmcli-core/src/main/java/pub/dtm/client/tcc/Tcc.java b/dtmcli-core/src/main/java/pub/dtm/client/tcc/Tcc.java new file mode 100644 index 0000000..1f36242 --- /dev/null +++ b/dtmcli-core/src/main/java/pub/dtm/client/tcc/Tcc.java @@ -0,0 +1,182 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.tcc; + +import lombok.NoArgsConstructor; +import pub.dtm.client.base.BranchIdGenerator; +import pub.dtm.client.constant.Constants; +import pub.dtm.client.constant.ParamFieldConstants; +import pub.dtm.client.enums.TransTypeEnum; +import pub.dtm.client.exception.FailureException; +import pub.dtm.client.interfaces.stub.IDtmServerStub; +import pub.dtm.client.interfaces.dtm.DtmConsumer; +import pub.dtm.client.model.dtm.TransBase; +import pub.dtm.client.model.feign.ServiceMessage; +import okhttp3.Response; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import pub.dtm.client.model.param.OperatorParam; +import pub.dtm.client.model.param.TccOperatorParam; +import pub.dtm.client.model.responses.DtmResponse; +import pub.dtm.client.utils.FeignUtils; +import pub.dtm.client.utils.HttpUtils; +import pub.dtm.client.utils.JsonUtils; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +/** + * Tcc trans type service + * + * @author horseLk + */ +@NoArgsConstructor +public class Tcc extends TransBase { + private static final Logger log = LoggerFactory.getLogger(Tcc.class); + + private static final String OP = "try"; + + /** + * branch id generator + */ + private BranchIdGenerator branchIdGenerator; + + /** + * feign client + */ + private IDtmServerStub dtmServerStub; + + public Tcc(String gid, IDtmServerStub dtmServerStub) { + super(gid, TransTypeEnum.TCC, false); + this.branchIdGenerator = new BranchIdGenerator(Constants.EMPTY_STRING); + this.dtmServerStub = dtmServerStub; + } + + public void setDtmServerStub(IDtmServerStub dtmServerStub) { + this.dtmServerStub = dtmServerStub; + } + + /** + * start a tcc distribute transaction + * @param consumer consumer + * @return gid + * @throws Exception exception + */ + public String tccGlobalTransaction(DtmConsumer consumer) throws Exception { + // if tcc's gid is empty, need to request a new gid from dtm svr + if (StringUtils.isEmpty(this.getGid())) { + this.setGid(FeignUtils.parseGid(dtmServerStub.newGid())); + } + log.info("the tcc transaction's gid is {}", this.getGid()); + + OperatorParam operatorParam = new OperatorParam(this.getGid(), TransTypeEnum.TCC); + DtmResponse resp = dtmServerStub.prepare(operatorParam); + log.info("prepare response: {}", resp); + if (!Constants.SUCCESS_RESULT.equals(resp.getDtmResult())) { + log.error("TCC transaction prepare fail. returned dtm_result is: {}, transaction gid: {}", resp.getDtmResult(), this.getGid()); + throw new FailureException("TCC Transaction prepare fail"); + } + try { + consumer.accept(this); + dtmServerStub.submit(operatorParam); + } catch (Exception e) { + log.error("TCC transaction submit fail, start abort it. transaction gid: {}", this.getGid()); + dtmServerStub.abort(operatorParam); + throw new FailureException(e); + } + return this.getGid(); + } + + /** + * busi can call method callBranch() to set tcc transaction's branch. + * the callBranch for micro service driver + * @param body busi body + * @param tryMessage service message of try operator + * @param confirmMessage service message of confirm operator + * @param cancelMessage service message of cancel operator + * @return feign response + * @throws Exception exception + */ + public feign.Response callBranch(Object body, ServiceMessage tryMessage, ServiceMessage confirmMessage, ServiceMessage cancelMessage) throws Exception { + log.info("call method Tcc.callBranch, tryMessage: {}, confirmMessage: {}, cancelMessage: {}", + JsonUtils.toJson(tryMessage), JsonUtils.toJson(confirmMessage), JsonUtils.toJson(cancelMessage)); + String branchId = this.branchIdGenerator.genBranchId(); + + TccOperatorParam operatorParam = new TccOperatorParam(this.getGid(), TransTypeEnum.TCC, branchId, Constants.DEFAULT_STATUS, + JsonUtils.toJson(body), FeignUtils.generatorURI(confirmMessage, false), FeignUtils.generatorURI(cancelMessage, false)); + DtmResponse resp = dtmServerStub.registerBranch(operatorParam); + if (!Constants.SUCCESS_RESULT.equals(resp.getDtmResult())) { + log.error("TCC transaction register branch fail. transaction gid: {}", this.getGid()); + throw new FailureException("TCC Transaction register branch fail"); + } + + Map paramsMap = new HashMap<>(); + paramsMap.put(ParamFieldConstants.GID, this.getGid()); + paramsMap.put(ParamFieldConstants.TRANS_TYPE, TransTypeEnum.TCC.getValue()); + paramsMap.put(ParamFieldConstants.BRANCH_ID, branchId); + paramsMap.put(ParamFieldConstants.OP, OP); + + feign.Response response = dtmServerStub.busiPost(new URI(FeignUtils.generatorURI(tryMessage, true)), + tryMessage.getPath(), paramsMap, body); + log.info("busi post is: {}", response); + FeignUtils.checkResult(response); + return response; + } + + /** + * busi can call method callBranch() to set tcc transaction's branch. + * the callBranch for http driver + * @param body busi body + * @param tryUrl http url of try operator + * @param confirmUrl http url of confirm operator + * @param cancelUrl http url of cancel operator + * @return http response + * @throws Exception exception + */ + public Response callBranch(Object body, String tryUrl, String confirmUrl, String cancelUrl) throws Exception { + log.info("call method Tcc.callBranch, tryUrl: {}, confirmUrl: {}, cancelUrl: {}", tryUrl, confirmUrl, cancelUrl); + String branchId = this.branchIdGenerator.genBranchId(); + + TccOperatorParam operatorParam = new TccOperatorParam(this.getGid(), TransTypeEnum.TCC, branchId, Constants.DEFAULT_STATUS, + JsonUtils.toJson(body), confirmUrl, cancelUrl); + DtmResponse resp = dtmServerStub.registerBranch(operatorParam); + if (!Constants.SUCCESS_RESULT.equals(resp.getDtmResult())) { + log.error("TCC transaction register branch fail. transaction gid: {}", this.getGid()); + throw new FailureException("TCC Transaction register branch fail"); + } + + Map paramsMap = new HashMap<>(); + paramsMap.put(ParamFieldConstants.GID, this.getGid()); + paramsMap.put(ParamFieldConstants.TRANS_TYPE, TransTypeEnum.TCC.getValue()); + paramsMap.put(ParamFieldConstants.BRANCH_ID, branchId); + paramsMap.put(ParamFieldConstants.OP, OP); + Response tryResponse = HttpUtils.post(HttpUtils.splicingUrl(tryUrl, paramsMap), JsonUtils.toJson(body)); + log.info("try response is: {}", tryResponse); + HttpUtils.checkResult(tryResponse); + return tryResponse; + } +} diff --git a/dtmcli-java/pom.xml b/dtmcli-java/pom.xml new file mode 100644 index 0000000..d09f884 --- /dev/null +++ b/dtmcli-java/pom.xml @@ -0,0 +1,48 @@ + + + + dtmcli-java-parent + io.github.dtm-labs + 2.1.4 + + 4.0.0 + + dtmcli-java + 2.1.4 + jar + dtmcli-java + + + UTF-8 + 1.8 + 1.8 + + + + + io.github.dtm-labs + dtmcli-common + 2.1.4 + + + + io.github.dtm-labs + dtmcli-core + 2.1.4 + + + + com.alibaba.nacos + nacos-client + + + + io.github.openfeign + feign-jackson + + + + + \ No newline at end of file diff --git a/dtmcli-java/src/main/java/pub/dtm/client/DtmClient.java b/dtmcli-java/src/main/java/pub/dtm/client/DtmClient.java new file mode 100644 index 0000000..85085e2 --- /dev/null +++ b/dtmcli-java/src/main/java/pub/dtm/client/DtmClient.java @@ -0,0 +1,174 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import feign.jackson.JacksonDecoder; +import feign.jackson.JacksonEncoder; +import pub.dtm.client.constant.Constants; +import pub.dtm.client.stub.DtmFeignClient; +import feign.Feign; +import pub.dtm.client.stub.URIParser; +import pub.dtm.client.interfaces.dtm.DtmConsumer; +import pub.dtm.client.interfaces.stub.IDtmServerStub; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import pub.dtm.client.properties.DtmProperties; +import pub.dtm.client.saga.Saga; +import pub.dtm.client.tcc.Tcc; +import pub.dtm.client.utils.NacosUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static com.alibaba.nacos.api.common.Constants.DEFAULT_CLUSTER_NAME; +import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; +import static com.alibaba.nacos.api.naming.CommonParams.CLUSTER_NAME; +import static com.alibaba.nacos.api.naming.CommonParams.GROUP_NAME; + +public class DtmClient { + private static final Logger log = LoggerFactory.getLogger(DtmClient.class); + + private IDtmServerStub dtmServerStub; + + public DtmClient() { + // init URIParser + new URIParser(); + + String endpoint = null; + try { + // redirect connect to dtm + endpoint = DtmProperties.get("dtm.ipport"); + // connect to dtm by nacos + if (StringUtils.isEmpty(endpoint)) { + Instance instance = NacosUtils.selectOneHealthyInstance(DtmProperties.get(Constants.MICRO_SERVICE_NAME_KEY), + DtmProperties.getOrDefault(GROUP_NAME, DEFAULT_GROUP), genClusters(DtmProperties.get(CLUSTER_NAME))); + endpoint = instance.toInetAddr(); + } + } catch (Exception e) { + log.error("initial dtm client for java error.", e); + System.exit(-1); + } + if (StringUtils.isEmpty(endpoint)) { + log.error("can not resolve dtm server message from config file, you can use nacos or redirect configure to config it."); + System.exit(-1); + } + IDtmServerStub feignClient = Feign + .builder() + .decoder(new JacksonDecoder()) + .encoder(new JacksonEncoder()) +// if you need read detail log of feign, please cancel the note. +// .logLevel(feign.Logger.Level.FULL) +// .logger(new DtmFeignLogger()) + .target(DtmFeignClient.class, Constants.HTTP_PREFIX + endpoint); + if (feignClient == null) { + log.error("initial dtm client for java error, feign client can't be null."); + System.exit(-1); + } + + this.dtmServerStub = feignClient; + } + + public DtmClient(String endpoint) { + // init URIParser + new URIParser(); + + if (StringUtils.isEmpty(endpoint)) { + log.error("dtm server endpoint can not be empty."); + System.exit(-1); + } + IDtmServerStub feignClient = Feign + .builder() + .decoder(new JacksonDecoder()) + .encoder(new JacksonEncoder()) +// if you need read detail log of feign, please cancel the note. +// .logLevel(feign.Logger.Level.FULL) +// .logger(new DtmFeignLogger()) + .target(DtmFeignClient.class, Constants.HTTP_PREFIX + endpoint); + + if (feignClient == null) { + log.error("initial dtm client for java error, feign client can't be null."); + System.exit(-1); + } + + this.dtmServerStub = feignClient; + } + + public DtmClient(IDtmServerStub dtmServerStub) { + this.dtmServerStub = dtmServerStub; + } + + private List genClusters(String clusterStr) { + if (StringUtils.isEmpty(clusterStr)) { + List clusters = new ArrayList<>(); + clusters.add(DEFAULT_CLUSTER_NAME); + return clusters; + } + String[] split = StringUtils.split(clusterStr, ","); + return Arrays.asList(split); + } + + /** + * start a tcc transaction without gid, client send a request to dtm svr for obtain a new gid. + * @param function consumer + * @return gid + * @throws Exception exception + */ + public String tccGlobalTransaction(DtmConsumer function) throws Exception { + Tcc tcc = new Tcc(null, dtmServerStub); + return tcc.tccGlobalTransaction(function); + } + + /** + * start a tcc transaction with a custom gid. + * @param gid gid + * @param function consumer + * @return gid + * @throws Exception exception + */ + public String tccGlobalTransaction(String gid, DtmConsumer function) throws Exception { + Tcc tcc = new Tcc(gid, dtmServerStub); + return tcc.tccGlobalTransaction(function); + } + + /** + * start a saga transaction with custom gid + * @param gid gid + * @return Saga + */ + public Saga newSaga(String gid) { + return new Saga(gid, dtmServerStub); + } + + /** + * start a saga transaction without gid, client send a request to dtm svr for obtain a new gid. + * @return Saga + */ + public Saga newSaga() { + return new Saga(null, dtmServerStub); + } +} diff --git a/dtmcli-java/src/main/java/pub/dtm/client/properties/DtmProperties.java b/dtmcli-java/src/main/java/pub/dtm/client/properties/DtmProperties.java new file mode 100644 index 0000000..7f8c156 --- /dev/null +++ b/dtmcli-java/src/main/java/pub/dtm/client/properties/DtmProperties.java @@ -0,0 +1,67 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.properties; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + + +/** + * Load properties of dtm server + * + * @author horse + */ +public class DtmProperties { + private static Properties dtmProperties; + + private static void loadNacosProperties() throws IOException { + Properties properties = new Properties(); + FileInputStream in = new FileInputStream(DtmProperties.class.getResource("/dtm-conf.properties").getPath()); + properties.load(in); + dtmProperties = properties; + } + + public static String get(String key) throws IOException { + if (dtmProperties == null) { + loadNacosProperties(); + } + return dtmProperties.getProperty(key); + } + + public static String getOrDefault(String key, String defaultValue) throws IOException { + if (dtmProperties == null) { + loadNacosProperties(); + } + return dtmProperties.getProperty(key, defaultValue); + } + + public static Properties getNacosProperties() throws IOException { + if (dtmProperties == null) { + loadNacosProperties(); + } + return dtmProperties; + } +} diff --git a/dtmcli-java/src/main/java/pub/dtm/client/stub/DtmFeignClient.java b/dtmcli-java/src/main/java/pub/dtm/client/stub/DtmFeignClient.java new file mode 100644 index 0000000..1afbeb3 --- /dev/null +++ b/dtmcli-java/src/main/java/pub/dtm/client/stub/DtmFeignClient.java @@ -0,0 +1,83 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.stub; + +import feign.Headers; +import feign.Param; +import feign.QueryMap; +import feign.RequestLine; +import feign.Response; +import pub.dtm.client.constant.Constants; +import pub.dtm.client.interfaces.stub.IDtmServerStub; +import pub.dtm.client.model.param.OperatorParam; +import pub.dtm.client.model.responses.DtmResponse; + +import java.net.URI; +import java.util.Map; + +/** + * IDtmServerStub implements for open-feign + * + * @author horse + */ +@Headers("Content-Type: application/json") +public interface DtmFeignClient extends IDtmServerStub { + @Override + default String stubType() { + return "open-feign"; + } + + @Override + @RequestLine(Constants.GET_METHOD + Constants.NEW_GID_URL) + DtmResponse newGid(); + + @Override + @RequestLine(Constants.GET_METHOD + Constants.PING_URL) + DtmResponse ping(); + + @Override + @RequestLine(Constants.POST_METHOD + Constants.PREPARE_URL) + DtmResponse prepare(OperatorParam body); + + @Override + @RequestLine(Constants.POST_METHOD + Constants.SUBMIT_URL) + DtmResponse submit(OperatorParam body); + + @Override + @RequestLine(Constants.POST_METHOD + Constants.ABORT_URL) + DtmResponse abort(OperatorParam body); + + @Override + @RequestLine(Constants.POST_METHOD + Constants.REGISTER_BRANCH_URL) + DtmResponse registerBranch(OperatorParam body); + + @Override + @RequestLine(Constants.GET_METHOD + "{path}") + Response busiGet(URI host, @Param("path") String path, @QueryMap Map queryMap); + + @Override + @RequestLine(Constants.POST_METHOD + "{path}") + Response busiPost(URI host, @Param("path") String path, @QueryMap Map queryMap, Object body); +} diff --git a/dtmcli-java/src/main/java/pub/dtm/client/stub/URIParser.java b/dtmcli-java/src/main/java/pub/dtm/client/stub/URIParser.java new file mode 100644 index 0000000..e62b1b3 --- /dev/null +++ b/dtmcli-java/src/main/java/pub/dtm/client/stub/URIParser.java @@ -0,0 +1,54 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.stub; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import pub.dtm.client.constant.Constants; +import pub.dtm.client.interfaces.stub.IURIParser; +import pub.dtm.client.model.feign.ServiceMessage; +import pub.dtm.client.properties.DtmProperties; +import pub.dtm.client.utils.FeignUtils; +import pub.dtm.client.utils.NacosUtils; + +/** + * Parse url to dtm server for java client. + * + * @author horse + */ +public class URIParser implements IURIParser { + static { + FeignUtils.setUriParser(new URIParser()); + } + + @Override + public String generatorURI(ServiceMessage serviceMessage, boolean httpType) throws Exception { + if (httpType) { + Instance instance = NacosUtils.selectOneHealthyInstance(serviceMessage.getServiceName(), + serviceMessage.getGroupName(), serviceMessage.getCluster()); + return Constants.HTTP_PREFIX + instance.toInetAddr(); + } + return DtmProperties.get("dtm.service.registryType") + "://" + serviceMessage.toString(); + } +} diff --git a/dtmcli-java/src/main/java/pub/dtm/client/utils/NacosUtils.java b/dtmcli-java/src/main/java/pub/dtm/client/utils/NacosUtils.java new file mode 100644 index 0000000..da45fd8 --- /dev/null +++ b/dtmcli-java/src/main/java/pub/dtm/client/utils/NacosUtils.java @@ -0,0 +1,52 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.utils; + +import com.alibaba.nacos.api.naming.NamingFactory; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Instance; +import pub.dtm.client.properties.DtmProperties; + +import java.util.List; + +/** + * Nacos utils + * + * @author horse + */ +public class NacosUtils { + private static NamingService namingService; + + public static void buildNamingService() throws Exception { + NacosUtils.namingService = NamingFactory.createNamingService(DtmProperties.getNacosProperties()); + } + + public static Instance selectOneHealthyInstance(String serviceName, String groupName, List cluster) throws Exception { + if (namingService == null) { + buildNamingService(); + } + return namingService.selectOneHealthyInstance(serviceName, groupName, cluster); + } +} diff --git a/dtmcli-springcloud/pom.xml b/dtmcli-springcloud/pom.xml new file mode 100644 index 0000000..dae4171 --- /dev/null +++ b/dtmcli-springcloud/pom.xml @@ -0,0 +1,70 @@ + + + + dtmcli-java-parent + io.github.dtm-labs + 2.1.4 + + 4.0.0 + + dtmcli-springcloud + 2.1.4.2 + jar + dtmcli-springcloud + + + UTF-8 + 1.8 + 1.8 + + 2.6.3 + 2021.0.1 + + + + + io.github.dtm-labs + dtmcli-common + 2.1.4 + + + + io.github.dtm-labs + dtmcli-core + 2.1.4 + + + + org.springframework.boot + spring-boot-starter + ${springboot.version} + + + + org.springframework.boot + spring-boot-configuration-processor + ${springboot.version} + true + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + \ No newline at end of file diff --git a/dtmcli-springcloud/src/main/java/pub/dtm/client/DtmClient.java b/dtmcli-springcloud/src/main/java/pub/dtm/client/DtmClient.java new file mode 100644 index 0000000..20db1e1 --- /dev/null +++ b/dtmcli-springcloud/src/main/java/pub/dtm/client/DtmClient.java @@ -0,0 +1,79 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import pub.dtm.client.interfaces.stub.IDtmServerStub; +import pub.dtm.client.interfaces.dtm.DtmConsumer; +import pub.dtm.client.saga.Saga; +import pub.dtm.client.tcc.Tcc; + +/** + * dtm client for spring + * + * @author horseLk + */ +@Component +public class DtmClient { + @Autowired + private IDtmServerStub dtmServerStub; + + /** + * start a tcc transaction without gid, client send a request to dtm svr for obtain a new gid. + * @return gid + */ + public String tccGlobalTransaction(DtmConsumer function) throws Exception { + Tcc tcc = new Tcc(null, dtmServerStub); + return tcc.tccGlobalTransaction(function); + } + + /** + * start a tcc transaction with custom gid + * @param gid gid + * @return gid + */ + public String tccGlobalTransaction(String gid, DtmConsumer function) throws Exception { + Tcc tcc = new Tcc(gid, dtmServerStub); + return tcc.tccGlobalTransaction(function); + } + + /** + * start a saga transaction with custom gid + * @param gid gid + * @return Saga + */ + public Saga newSaga(String gid) { + return new Saga(gid, dtmServerStub); + } + + /** + * start a saga transaction without gid, client send a request to dtm svr for obtain a new gid. + * @return Saga + */ + public Saga newSaga() { + return new Saga(null, dtmServerStub); + } +} diff --git a/dtmcli-springcloud/src/main/java/pub/dtm/client/configuration/DtmConfiguration.java b/dtmcli-springcloud/src/main/java/pub/dtm/client/configuration/DtmConfiguration.java new file mode 100644 index 0000000..7f53c22 --- /dev/null +++ b/dtmcli-springcloud/src/main/java/pub/dtm/client/configuration/DtmConfiguration.java @@ -0,0 +1,72 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.configuration; + +import pub.dtm.client.stub.URIParser; +import pub.dtm.client.properties.DtmProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +/** + * Dtm client configuration + * + * @author horse + */ +@Component +@ComponentScan({"pub.dtm.client"}) +@Configuration +@EnableFeignClients("pub.dtm.client.stub") +@EnableConfigurationProperties(DtmProperties.class) +public class DtmConfiguration { + @Autowired + private DtmProperties dtmProperties; + + @Bean + @ConditionalOnMissingBean(URIParser.class) + public URIParser uriParser() { + URIParser.setRegistryType(dtmProperties.getRegistryType()); + return new URIParser(); + } + + /** + * if you need read detail log, please cancel note. + */ +// @Bean +// Logger.Level feignLoggerLevel() { +// return Logger.Level.FULL; +// } +// +// @Bean +// Logger feignLogger() { +// return new DtmFeignLogger(); +// } + +} diff --git a/src/main/java/common/model/TransResponse.java b/dtmcli-springcloud/src/main/java/pub/dtm/client/properties/DtmProperties.java similarity index 74% rename from src/main/java/common/model/TransResponse.java rename to dtmcli-springcloud/src/main/java/pub/dtm/client/properties/DtmProperties.java index b9a6631..7ecd3b7 100644 --- a/src/main/java/common/model/TransResponse.java +++ b/dtmcli-springcloud/src/main/java/pub/dtm/client/properties/DtmProperties.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,23 +22,23 @@ * SOFTWARE. */ -package common.model; +package pub.dtm.client.properties; import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; /** - * @author lixiaoshuang + * Load properties of dtm server + * + * @author horse */ +@ConfigurationProperties(prefix = DtmProperties.PREFIX) @Data -public class TransResponse { +public class DtmProperties { + public static final String PREFIX = "dtm.service"; - private String dtmResult; + private String registryType; - public TransResponse(String dtmResult) { - this.dtmResult = dtmResult; - } + private String name; - public static TransResponse buildTransResponse(String result) { - return new TransResponse(result); - } } diff --git a/dtmcli-springcloud/src/main/java/pub/dtm/client/stub/DtmFeignClient.java b/dtmcli-springcloud/src/main/java/pub/dtm/client/stub/DtmFeignClient.java new file mode 100644 index 0000000..b1ffe93 --- /dev/null +++ b/dtmcli-springcloud/src/main/java/pub/dtm/client/stub/DtmFeignClient.java @@ -0,0 +1,86 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.stub; + +import feign.Response; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.cloud.openfeign.SpringQueryMap; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import pub.dtm.client.constant.Constants; +import pub.dtm.client.interfaces.stub.IDtmServerStub; +import pub.dtm.client.model.param.OperatorParam; +import pub.dtm.client.model.responses.DtmResponse; + +import java.net.URI; +import java.util.Map; + +/** + * IdtmServerStub implements for feign-spring + * + * @author horseLk + */ +@FeignClient(value = "${dtm.service.name}") +public interface DtmFeignClient extends IDtmServerStub { + @Override + default String stubType() { + return "feign-spring"; + } + + @Override + @GetMapping(Constants.NEW_GID_URL) + DtmResponse newGid(); + + @Override + @GetMapping(Constants.PING_URL) + DtmResponse ping(); + + @Override + @PostMapping(Constants.PREPARE_URL) + DtmResponse prepare(@RequestBody OperatorParam body); + + @Override + @PostMapping(Constants.SUBMIT_URL) + DtmResponse submit(@RequestBody OperatorParam body); + + @Override + @PostMapping(Constants.ABORT_URL) + DtmResponse abort(@RequestBody OperatorParam body); + + @Override + @PostMapping(Constants.REGISTER_BRANCH_URL) + DtmResponse registerBranch(@RequestBody OperatorParam body); + + @Override + @GetMapping(value = "{path}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + Response busiGet(URI host, @PathVariable("path") String path, @SpringQueryMap Map queryMap); + + @Override + @PostMapping(value = "{path}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + Response busiPost(URI host, @PathVariable("path") String path, @SpringQueryMap Map queryMap, @RequestBody Object body); +} diff --git a/dtmcli-springcloud/src/main/java/pub/dtm/client/stub/URIParser.java b/dtmcli-springcloud/src/main/java/pub/dtm/client/stub/URIParser.java new file mode 100644 index 0000000..a3b3bbf --- /dev/null +++ b/dtmcli-springcloud/src/main/java/pub/dtm/client/stub/URIParser.java @@ -0,0 +1,55 @@ +/* + * MIT License + * + * Copyright (c) 2022 dtm-labs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pub.dtm.client.stub; + +import pub.dtm.client.constant.Constants; +import pub.dtm.client.interfaces.stub.IURIParser; +import pub.dtm.client.model.feign.ServiceMessage; +import pub.dtm.client.utils.FeignUtils; + +/** + * Parse url to dtm server for spring cloud client. + * + * @author horse + */ +public class URIParser implements IURIParser { + static { + FeignUtils.setUriParser(new URIParser()); + } + + private static String registryType; + + public static void setRegistryType(String registryType) { + URIParser.registryType = registryType; + } + + @Override + public String generatorURI(ServiceMessage serviceMessage, boolean httpType) throws Exception { + if (httpType) { + return Constants.HTTP_PREFIX + serviceMessage.getServiceName(); + } + return registryType + "://" + serviceMessage.toString(); + } +} diff --git a/dtmcli-springcloud/src/main/resources/META-INF/spring.factories b/dtmcli-springcloud/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..f780708 --- /dev/null +++ b/dtmcli-springcloud/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=pub.dtm.client.configuration.DtmConfiguration \ No newline at end of file diff --git a/eureka-plugin/pom.xml b/eureka-plugin/pom.xml new file mode 100644 index 0000000..274fb49 --- /dev/null +++ b/eureka-plugin/pom.xml @@ -0,0 +1,58 @@ + + + + dtmcli-java-parent + io.github.dtm-labs + 2.1.4 + + 4.0.0 + + eureka-plugin + 2.1.4.2 + jar + eureka-plugin + + + UTF-8 + 1.8 + 1.8 + + 2.6.3 + 2021.0.1 + + + + + org.springframework.boot + spring-boot-starter + ${springboot.version} + + + + org.springframework.boot + spring-boot-configuration-processor + ${springboot.version} + true + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + \ No newline at end of file diff --git a/src/main/java/xa/Xa.java b/eureka-plugin/src/main/java/pub/dtm/client/configuration/EurekaConfiguration.java similarity index 81% rename from src/main/java/xa/Xa.java rename to eureka-plugin/src/main/java/pub/dtm/client/configuration/EurekaConfiguration.java index 3d394f9..f62a267 100644 --- a/src/main/java/xa/Xa.java +++ b/eureka-plugin/src/main/java/pub/dtm/client/configuration/EurekaConfiguration.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2021 yedf + * Copyright (c) 2022 dtm-labs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,15 @@ * SOFTWARE. */ -package xa; +package pub.dtm.client.configuration; -public class Xa { +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +/** + * Eureka configuration + * + * @author horseLk + */ +@EnableEurekaClient +public class EurekaConfiguration { } diff --git a/eureka-plugin/src/main/resources/META-INF/spring.factories b/eureka-plugin/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..ed9756f --- /dev/null +++ b/eureka-plugin/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=pub.dtm.client.configuration.EurekaConfiguration \ No newline at end of file diff --git a/nacos-plugin/pom.xml b/nacos-plugin/pom.xml new file mode 100644 index 0000000..1c3eceb --- /dev/null +++ b/nacos-plugin/pom.xml @@ -0,0 +1,70 @@ + + + + dtmcli-java-parent + io.github.dtm-labs + 2.1.4 + + 4.0.0 + + nacos-plugin + 2.1.4.2 + jar + nacos-plugin + + + UTF-8 + 1.8 + 1.8 + + 2021.0.1 + 2021.0.1.0 + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + + + com.netflix.ribbon + ribbon + + + + + + org.springframework.cloud + spring-cloud-loadbalancer + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${alibaba-cloud.version} + pom + import + + + + + + \ No newline at end of file diff --git a/pic_ref/newversion.png b/pic_ref/newversion.png new file mode 100644 index 0000000..57828ec Binary files /dev/null and b/pic_ref/newversion.png differ diff --git a/pic_ref/oldversion.png b/pic_ref/oldversion.png new file mode 100644 index 0000000..f4e0513 Binary files /dev/null and b/pic_ref/oldversion.png differ diff --git a/pom.xml b/pom.xml index 158117d..c81ae7a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,56 +1,276 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - - pub.dtm - dtmcli-java - 1.5.5-SNAPSHOT - + + io.github.dtm-labs + dtmcli-java-parent + 2.1.4 + pom + + dtmcli-java-parent + The java client for dtm + https://github.com/dtm-labs/dtmcli-java + + + dtmcli-common + dtmcli-core + dtmcli-springcloud + dtmcli-java + nacos-plugin + eureka-plugin + + - 8 - 8 - 1.18.12 - 1.2.78 - 4.9.1 - 3.12.0 - 1.7.30 - 8.0.27 + 1.8 + 1.8 + 1.8 UTF-8 + 4.12 + 2.12.2 + 1.18.0 + 11.8 + 3.12.0 + 3.14.9 + 1.4.2 + 1.7.30 - - - - com.alibaba - fastjson - ${fastjson.version} - - - org.projectlombok - lombok - ${lombok.version} - - - com.squareup.okhttp3 - okhttp - ${okhttp.version} - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - org.slf4j - slf4j-api - ${slf4j-api.version} - - - mysql - mysql-connector-java - ${mysql-connector-java.version} - - + + + + + junit + junit + ${junit.version} + test + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + org.projectlombok + lombok + ${lombok.version} + + + + io.github.openfeign + feign-core + ${feign.version} + + + + io.github.openfeign + feign-jackson + ${feign.version} + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + + + com.alibaba.nacos + nacos-client + ${nacos.version} + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + + + + + MIT + https://spdx.org/licenses/MIT.html + + + + https://github.com/dtm-labs/dtmcli-java.git + https://github.com/dtm-labs/dtmcli-java + + + + horseLk + horsekiao@gmail.com + + Developer + + +8 + + + + + + release + + + + src/main/java + + **/*.properties + **/*.sample + + + + dtmcli-common/src/main/java + + **/*.properties + **/*.sample + + + + dtmcli-core/src/main/java + + **/*.properties + **/*.sample + + + + dtmcli-java/src/main/java + + **/*.properties + **/*.sample + + + dtmcli-spring/src/main/java + + **/*.properties + **/*.sa + + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + ${project.build.sourceEncoding} + + + + package + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + private + true + UTF-8 + UTF-8 + UTF-8 + -Xdoclint:none + /Library/Java/JavaVirtualMachines/jdk1.8.0_261.jdk/Contents/Home/bin/javadoc + + + + + package + + jar + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + verify + + sign + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + 1.8 + 1.8 + true + true + UTF-8 + false + ${project.build.sourceEncoding} + + + + + org.apache.maven.plugins + maven-release-plugin + 2.5.1 + + + + + + ossrh + ossrh + https://s01.oss.sonatype.org/content/repositories/snapshots/ + + + ossrh + ossrh + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/client/DtmClient.java b/src/main/java/client/DtmClient.java deleted file mode 100644 index a57e553..0000000 --- a/src/main/java/client/DtmClient.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2021 yedf - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package client; - - -import com.alibaba.fastjson.JSONObject; -import common.model.DtmConsumer; -import common.model.DtmServerInfo; -import common.utils.HttpUtil; -import okhttp3.Response; -import saga.Saga; -import tcc.Tcc; - -import java.util.Objects; - -/** - * @author lixiaoshuang - */ -public class DtmClient { - - private String ipPort; - - public DtmClient(String ipPort) { - this.ipPort = ipPort; - } - - /** - * 生成全局事务id - * - * @return - * @throws Exception - */ - public String genGid() throws Exception { - DtmServerInfo dtmServerInfo = new DtmServerInfo(ipPort); - JSONObject jsonObject = null; - try { - Response response = HttpUtil.get(dtmServerInfo.newGid()); - if (Objects.nonNull(response.body())) { - String result = response.body().string(); - jsonObject = JSONObject.parseObject(result); - } - } catch (Exception e) { - throw new Exception("Can’t get gid, please check the dtm server."); - } - if (Objects.isNull(jsonObject)) { - throw new Exception("Can’t get gid, please check the dtm server."); - } - Object code = jsonObject.get("code"); - if (null != code && (int) code > 0) { - Object message = jsonObject.get("message"); - throw new Exception(message.toString()); - } - return jsonObject.get("gid").toString(); - } - - /** - * tcc事务 - * - * @param gid - * @param function - * @return - * @throws Exception - */ - public void tccGlobalTransaction(String gid, DtmConsumer function) throws Exception { - Tcc tcc = new Tcc(ipPort, gid); - tcc.tccGlobalTransaction(function); - } - - /** - * create a new saga - * @param gid - */ - public Saga newSaga(String gid) { - return new Saga(ipPort, gid); - } -} diff --git a/src/main/java/common/model/DtmServerInfo.java b/src/main/java/common/model/DtmServerInfo.java deleted file mode 100644 index c2fc8b2..0000000 --- a/src/main/java/common/model/DtmServerInfo.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2021 yedf - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package common.model; - -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * @author lixiaoshuang - */ -@Data -@NoArgsConstructor -public class DtmServerInfo { - - /** - * ip+port - */ - private String ipPort; - - - public static final String PREFIX = "http://"; - - public static final String BASE = "/api/dtmsvr"; - - public static final String NEW_GID = BASE + "/newGid"; - - public static final String PREPARE = BASE + "/prepare"; - - public static final String SUBMIT = BASE + "/submit"; - - public static final String ABORT = BASE + "/abort"; - - public static final String REGISTER_TCC_BRANCH = BASE + "/registerTccBranch"; - - public DtmServerInfo(String ipPort) { - this.ipPort = ipPort; - } - - /** - * 生成gid url - * - * @return - */ - public String newGid() { - return PREFIX + ipPort + NEW_GID; - } - - /** - * 生成gid url - * - * @return - */ - public String prepare() { - return PREFIX + ipPort + PREPARE; - } - - /** - * submit 阶段 url - * - * @return - */ - public String submit() { - return PREFIX + ipPort + SUBMIT; - } - - /** - * abort 阶段 url - * - * @return - */ - public String abort() { - return PREFIX + ipPort + ABORT; - } - - /** - * 注册tcc 事务分支 - * - * @return - */ - public String registerTccBranch() { - return PREFIX + ipPort + REGISTER_TCC_BRANCH; - } - -} diff --git a/src/main/java/common/utils/HttpUtil.java b/src/main/java/common/utils/HttpUtil.java deleted file mode 100644 index b608199..0000000 --- a/src/main/java/common/utils/HttpUtil.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2021 yedf - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package common.utils; - -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -/** - * @author lixiaoshuang - */ -public class HttpUtil { - - private static final OkHttpClient CLIENT = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS) - .readTimeout(5, TimeUnit.SECONDS).writeTimeout(5, TimeUnit.SECONDS).build(); - - public static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=utf-8"); - - /** - * get 请求 - * - * @param url - * @return - * @throws IOException - */ - public static Response get(String url) throws IOException { - Request request = new Request.Builder().url(url).get().build(); - return CLIENT.newCall(request).execute(); - } - - /** - * post 请求 - * - * @param url - * @param json - * @return - * @throws IOException - */ - public static Response post(String url, String json) throws IOException { - RequestBody body = RequestBody.create(MEDIA_TYPE, json); - Request request = new Request.Builder().url(url).post(body).build(); - return CLIENT.newCall(request).execute(); - } -} diff --git a/src/main/java/saga/Saga.java b/src/main/java/saga/Saga.java deleted file mode 100644 index 9a24e57..0000000 --- a/src/main/java/saga/Saga.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2021 yedf - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package saga; - -import com.alibaba.fastjson.JSONObject; -import common.constant.Constant; -import common.constant.ParamFieldConstant; -import common.model.DtmServerInfo; -import common.utils.HttpUtil; -import common.enums.TransTypeEnum; -import common.model.TransBase; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -public class Saga { - - private static final String ORDERS = "orders"; - - private static final String CONCURRENT = "concurrent"; - - private TransBase transBase; - - private DtmServerInfo dtmServerInfo; - - private boolean concurrent; - - private Map> orders; - - public Saga(String ipPort, String gid) { - this.dtmServerInfo = new DtmServerInfo(ipPort); - this.transBase = new TransBase(TransTypeEnum.SAGA, gid, false); - this.concurrent = false; - this.orders = new HashMap<>(); - } - - public Saga add(String action, String compensate, Object postData) { - HashMap step = new HashMap<>(); - step.put(ParamFieldConstant.ACTION, action); - step.put(ParamFieldConstant.COMPENSATE, compensate); - transBase.getSteps().add(step); - transBase.getPayloads().add(JSONObject.toJSONString(postData)); - return this; - } - - public Saga addBranchOrder(Integer branch, ArrayList preBranches) { - orders.put(branch.toString(), preBranches); - return this; - } - - public Saga enableConcurrent() { - concurrent = true; - return this; - } - - public void submit() throws Exception { - addConcurrentContext(); - HashMap mapParam = new HashMap<>(Constant.DEFAULT_INITIAL_CAPACITY); - mapParam.put(ParamFieldConstant.GID, transBase.getGid()); - mapParam.put(ParamFieldConstant.TRANS_TYPE, TransTypeEnum.SAGA.getValue()); - mapParam.put(ParamFieldConstant.STEPS, transBase.getSteps()); - mapParam.put(ParamFieldConstant.PAYLOADS, transBase.getPayloads()); - mapParam.put(ParamFieldConstant.CUSTOM_DATA, transBase.getCustomData()); - mapParam.put(ParamFieldConstant.WAIT_RESULT, transBase.isWaitResult()); - mapParam.put(ParamFieldConstant.TIMEOUT_TO_FAIL, transBase.getTimeoutToFail()); - mapParam.put(ParamFieldConstant.RETRY_INTERVAL, transBase.getRetryInterval()); - mapParam.put(ParamFieldConstant.PASSTHROGH_HEADERS, transBase.getPassthroughHeaders()); - mapParam.put(ParamFieldConstant.BRANCH_HEADERS, transBase.getBranchHeaders()); - - HttpUtil.post(dtmServerInfo.submit(), JSONObject.toJSONString(mapParam)); - } - - public Saga enableWaitResult() { - transBase.setWaitResult(true); - return this; - } - - public Saga setTimeoutToFail(long timeoutToFail) { - transBase.setTimeoutToFail(timeoutToFail); - return this; - } - - public Saga setRetryInterval(long retryInterval) { - transBase.setRetryInterval(retryInterval); - return this; - } - - public Saga setBranchHeaders(Map headers) { - transBase.setBranchHeaders(headers); - return this; - } - - public Saga setPassthroughHeaders(ArrayList passthroughHeaders) { - transBase.setPassthroughHeaders(passthroughHeaders); - return this; - } - - private void addConcurrentContext() { - if (concurrent) { - HashMap data = new HashMap<>(); - data.put(ORDERS, orders); - data.put(CONCURRENT, true); - transBase.setCustomData(JSONObject.toJSONString(data)); - } - } -} diff --git a/src/main/java/tcc/Tcc.java b/src/main/java/tcc/Tcc.java deleted file mode 100644 index b0e3ca9..0000000 --- a/src/main/java/tcc/Tcc.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2021 yedf - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tcc; - -import com.alibaba.fastjson.JSONObject; -import common.constant.Constant; -import common.model.DtmConsumer; -import common.model.DtmServerInfo; -import common.utils.HttpUtil; -import common.utils.BranchIdGeneratorUtil; -import common.constant.ParamFieldConstant; -import common.enums.TransTypeEnum; -import common.model.TransBase; -import exception.FailureException; -import okhttp3.Response; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; - -/** - * @author lixiaoshuang - */ -public class Tcc { - - private static final String DEFAULT_STATUS = "prepared"; - - private static final String OP = "try"; - - private static final String FAIL_RESULT = "FAILURE"; - - Logger log = LoggerFactory.getLogger(Tcc.class); - - - /** - * 事务信息 - */ - private TransBase transBase; - - /** - * server 信息 - */ - private DtmServerInfo dtmServerInfo; - - /** - * id 生成器 - */ - private BranchIdGeneratorUtil branchIdGeneratorUtil; - - public Tcc(String ipPort, String gid) { - this.dtmServerInfo = new DtmServerInfo(ipPort); - this.branchIdGeneratorUtil = new BranchIdGeneratorUtil(""); - this.transBase = new TransBase(TransTypeEnum.TCC, gid, false); - } - - public void tccGlobalTransaction(DtmConsumer consumer) throws Exception { - HashMap paramMap = new HashMap<>(Constant.DEFAULT_INITIAL_CAPACITY); - paramMap.put(ParamFieldConstant.GID, transBase.getGid()); - paramMap.put(ParamFieldConstant.TRANS_TYPE, TransTypeEnum.TCC.getValue()); - - try { - Response response = HttpUtil.post(dtmServerInfo.prepare(), JSONObject.toJSONString(paramMap)); - this.checkResult(response); - } catch (FailureException failureException) { - log.info("tccGlobalTransaction fail message:{}" + failureException.getLocalizedMessage()); - throw failureException; - } - - try { - consumer.accept(this); - HttpUtil.post(dtmServerInfo.submit(), JSONObject.toJSONString(paramMap)); - } catch (Exception e) { - HttpUtil.post(dtmServerInfo.abort(), JSONObject.toJSONString(paramMap)); - throw e; - } - } - - public Response callBranch(Object body, String tryUrl, String confirmUrl, String cancelUrl) throws Exception { - String branchId = branchIdGeneratorUtil.genBranchId(); - HashMap registerParam = new HashMap<>(Constant.DEFAULT_INITIAL_CAPACITY); - registerParam.put(ParamFieldConstant.GID, transBase.getGid()); - registerParam.put(ParamFieldConstant.BRANCH_ID, branchId); - registerParam.put(ParamFieldConstant.TRANS_TYPE, TransTypeEnum.TCC.getValue()); - registerParam.put(ParamFieldConstant.STATUS, DEFAULT_STATUS); - registerParam.put(ParamFieldConstant.DATA, JSONObject.toJSONString(body)); - registerParam.put(ParamFieldConstant.TRY, tryUrl); - registerParam.put(ParamFieldConstant.CONFIRM, confirmUrl); - registerParam.put(ParamFieldConstant.CANCEL, cancelUrl); - - Response registerResponse = HttpUtil - .post(dtmServerInfo.registerTccBranch(), JSONObject.toJSONString(registerParam)); - this.checkResult(registerResponse); - - Response tryResponse = HttpUtil - .post(splicingTryUrl(tryUrl, transBase.getGid(), TransTypeEnum.TCC.getValue(), branchId, OP), - JSONObject.toJSONString(body)); - this.checkResult(tryResponse); - - return tryResponse; - } - - /** - * 和go 保持同样的发送方式 参数拼在url后边 - */ - private String splicingTryUrl(String tryUrl, String gid, String transType, String branchId, String op) { - return tryUrl + "?gid=" + gid + "&trans_type=" + transType + "&branch_id=" + branchId + "&op=" + op; - } - - - public void checkResult(Response response)throws Exception { - int errorCode = 400; - if (response.code() >= errorCode){ - throw new FailureException(response.message()); - } - String result = response.body().string(); - if (StringUtils.isBlank(result)) { - throw new FailureException("response is null"); - } - if (result.contains(FAIL_RESULT)){ - throw new FailureException("Service returned failed"); - } - } -} \ No newline at end of file