Compare commits
2 Commits
master
...
issues/I9F
Author | SHA1 | Date |
---|---|---|
![]() |
bc86356078 | |
![]() |
33197922d6 |
|
@ -11,7 +11,7 @@
|
|||
## Overview
|
||||
LiteFlow is a lightweight and powerful rules engine framework, which can be used in the field of complex componenzed business orchestration. DSL rules drive the whole complex business, and can achieve smooth refresh hot deployment, supporting the embedding of multiple scripting language rules. Help the system become more silky and flexible.
|
||||
|
||||
LiteFlow was officially open-sourced in 2020 and has since become an indispensable presence in the field of open-source rule engines in China. What's more, the most crucial aspect is that LiteFlow is an open-source project that continues to iterate at a high speed.
|
||||
LiteFlow was officially open source in 2020 and won the title of "the Most Popular Open Source software" in China in 2021. Gitee-GVP award in 2022. It is an open source project that is growing rapidly.
|
||||
|
||||
LiteFlow is a community-driven project. We take community building very seriously. We have a community of more than 4000 users who can respond to any problems or suggestions they encounter.
|
||||
|
||||
|
@ -31,7 +31,7 @@ You can find out how to join the community on the official website!
|
|||
* **Wide support:** LiteFlow works regardless of whether your project is built on Springboot, Spring, or any other Java framework.
|
||||
* **JDK support:** From JDK8 to JDK17. Don't worry about JDK versions.
|
||||
* **Full Springboot support:** Supports Springboot 2.X through the latest Springboot 3.X.
|
||||
* **Scripting language support:** You can define script language nodes that support Groovy, Javascript, QLExpress, Python, Lua, Kotlin and Aviator. More script languages will be supported in the future.
|
||||
* **Scripting language support:** You can define script language nodes that support Groovy, Javascript, QLExpress, Python, Lua, and Aviator. More script languages will be supported in the future.
|
||||
* **Rule nesting support:** You can use simple expressions to create multiple nested complex logic layouts if you want.
|
||||
* **Component retry support:** Components can support retry, and each component can customize the retry configuration and specify exceptions.
|
||||
* **Context isolation mechanism:** Reliable context isolation mechanism, you do not have to worry about high concurrency data flow.
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
## 🌈概述
|
||||
LiteFlow是一个轻量且强大的国产规则引擎框架,可用于复杂的组件化业务的编排领域,独有的DSL规则驱动整个复杂业务,并可实现平滑刷新热部署,支持多种脚本语言规则的嵌入。帮助系统变得更加丝滑且灵活。
|
||||
|
||||
LiteFlow于2020年正式开源,直到现在已经是国内开源规则引擎中不可忽视的存在,而且最关键的是,LiteFlow还是一个持续高速迭代的开源项目。
|
||||
LiteFlow于2020年正式开源,2021年获得开源中国年度最受欢迎开源软件殊荣。于2022年获得Gitee最有价值开源项目(GVP)荣誉。是一个正处在高速发展中的开源项目。
|
||||
|
||||
LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥有一个5000多人的使用者社区,在使用中碰到任何问题或者建议都可以在社区中反应。
|
||||
LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥有一个4000多人的使用者社区,在使用中碰到任何问题或者建议都可以在社区中反应。
|
||||
|
||||
你在官网中可以找到加入社区的方式!
|
||||
|
||||
|
@ -29,7 +29,7 @@ LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥
|
|||
* **支持广泛:** 不管你的项目是不是基于Springboot,Spring还是任何其他java框架构建,LiteFlow都能游刃有余。
|
||||
* **JDK支持:** 从JDK8到JDK17,全部支持。无需担心JDK版本。
|
||||
* **Springboot支持全面:** 支持Springboot 2.X到最新的Springboot 3.X。
|
||||
* **脚本语言支持:** 可以定义脚本语言节点,支持Groovy,Javascript,QLExpress,Python,Lua,Aviator,Java,Kotlin。未来还会支持更多的脚本语言。
|
||||
* **脚本语言支持:** 可以定义脚本语言节点,支持Groovy,Javascript,QLExpress,Python,Lua,Aviator,Java。未来还会支持更多的脚本语言。
|
||||
* **脚本和Java全打通:** 所有脚本语言均可调用Java方法,甚至于可以引用任意的实例,在脚本中调用RPC也是支持的。
|
||||
* **规则嵌套支持:** 只要你想的出,你可以利用简单的表达式完成多重嵌套的复杂逻辑编排。
|
||||
* **组件重试支持:** 组件可以支持重试,每个组件均可自定义重试配置和指定异常。
|
||||
|
|
|
@ -136,7 +136,8 @@ public class LiteFlowChainELBuilder {
|
|||
|
||||
public LiteFlowChainELBuilder setRoute(String routeEl){
|
||||
if (StrUtil.isBlank(routeEl)) {
|
||||
return this;
|
||||
String errMsg = StrUtil.format("You have defined the label <route> but there is no el in the chain route[{}].", chain.getChainId());
|
||||
throw new FlowSystemException(errMsg);
|
||||
}
|
||||
List<String> errorList = new ArrayList<>();
|
||||
try {
|
||||
|
@ -182,6 +183,15 @@ public class LiteFlowChainELBuilder {
|
|||
}
|
||||
|
||||
this.chain.setEl(elStr);
|
||||
|
||||
// 判断是否已经包含了这个EL
|
||||
if (this.chain.isExist()) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("chain[{}] el[{}] is already contains, skip", chain.getChainId(), elStr);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
// 如果设置了不检查Node是否存在,那么这里是不解析的
|
||||
if (liteflowConfig.getParseMode().equals(ParseModeEnum.PARSE_ONE_ON_FIRST_EXEC)){
|
||||
|
@ -233,9 +243,6 @@ public class LiteFlowChainELBuilder {
|
|||
}
|
||||
|
||||
public LiteFlowChainELBuilder setNamespace(String nameSpace){
|
||||
if (StrUtil.isBlank(nameSpace)) {
|
||||
nameSpace = ChainConstant.DEFAULT_NAMESPACE;
|
||||
}
|
||||
this.chain.setNamespace(nameSpace);
|
||||
return this;
|
||||
}
|
||||
|
@ -258,6 +265,17 @@ public class LiteFlowChainELBuilder {
|
|||
}
|
||||
|
||||
public void build() {
|
||||
|
||||
// 如果不用是新的chain,不需要更新
|
||||
if (chain.isExist()) {
|
||||
return;
|
||||
} else {
|
||||
// 如果是新的chain,需要更新
|
||||
if (StrUtil.isNotBlank(chain.getEl())){
|
||||
chain.setChainSha256();
|
||||
}
|
||||
}
|
||||
|
||||
this.chain.setRouteItem(this.route);
|
||||
this.chain.setConditionList(this.conditionList);
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.yomahub.liteflow.enums;
|
|||
|
||||
public enum ScriptTypeEnum {
|
||||
|
||||
CUSTOM("custom", "custom"),
|
||||
GROOVY("groovy", "groovy"),
|
||||
QLEXPRESS("qlexpress", "qlexpress"),
|
||||
JS("javascript", "js"),
|
||||
|
|
|
@ -10,199 +10,228 @@ package com.yomahub.liteflow.flow.element;
|
|||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.exception.ChainEndException;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
import com.yomahub.liteflow.enums.ExecuteableTypeEnum;
|
||||
import com.yomahub.liteflow.exception.FlowSystemException;
|
||||
import com.yomahub.liteflow.util.Sha256Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* chain对象,实现可执行器
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class Chain implements Executable{
|
||||
public class Chain implements Executable {
|
||||
|
||||
private static final LFLog LOG = LFLoggerManager.getLogger(Chain.class);
|
||||
private static final LFLog LOG = LFLoggerManager.getLogger(Chain.class);
|
||||
|
||||
private String chainId;
|
||||
private String chainId;
|
||||
|
||||
private Executable routeItem;
|
||||
private String chainSha256;
|
||||
|
||||
private List<Condition> conditionList = new ArrayList<>();
|
||||
private Executable routeItem;
|
||||
|
||||
private String el;
|
||||
private List<Condition> conditionList = new ArrayList<>();
|
||||
|
||||
private boolean isCompiled = true;
|
||||
private String el;
|
||||
|
||||
private String namespace;
|
||||
private boolean isCompiled = true;
|
||||
|
||||
public Chain(String chainName) {
|
||||
this.chainId = chainName;
|
||||
}
|
||||
private String namespace;
|
||||
|
||||
public Chain() {
|
||||
}
|
||||
public Chain(String chainName) {
|
||||
this.chainId = chainName;
|
||||
}
|
||||
|
||||
public Chain(String chainName, List<Condition> conditionList) {
|
||||
this.chainId = chainName;
|
||||
this.conditionList = conditionList;
|
||||
}
|
||||
public Chain() {
|
||||
}
|
||||
|
||||
public List<Condition> getConditionList() {
|
||||
return conditionList;
|
||||
}
|
||||
public Chain(String chainName, List<Condition> conditionList) {
|
||||
this.chainId = chainName;
|
||||
this.conditionList = conditionList;
|
||||
}
|
||||
|
||||
public void setConditionList(List<Condition> conditionList) {
|
||||
this.conditionList = conditionList;
|
||||
}
|
||||
public List<Condition> getConditionList() {
|
||||
return conditionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 请使用{@link #getChainId()}
|
||||
*/
|
||||
@Deprecated
|
||||
public String getChainName() {
|
||||
return chainId;
|
||||
}
|
||||
public void setConditionList(List<Condition> conditionList) {
|
||||
this.conditionList = conditionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chainName
|
||||
* @deprecated 请使用 {@link #setChainId(String)}
|
||||
*/
|
||||
public void setChainName(String chainName) {
|
||||
this.chainId = chainName;
|
||||
}
|
||||
/**
|
||||
* @deprecated 请使用{@link #getChainId()}
|
||||
*/
|
||||
@Deprecated
|
||||
public String getChainName() {
|
||||
return chainId;
|
||||
}
|
||||
|
||||
public String getChainId() {
|
||||
return chainId;
|
||||
}
|
||||
/**
|
||||
* @param chainName
|
||||
* @deprecated 请使用 {@link #setChainId(String)}
|
||||
*/
|
||||
public void setChainName(String chainName) {
|
||||
this.chainId = chainName;
|
||||
}
|
||||
|
||||
public void setChainId(String chainId) {
|
||||
this.chainId = chainId;
|
||||
}
|
||||
public String getChainId() {
|
||||
return chainId;
|
||||
}
|
||||
|
||||
// 执行chain的主方法
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
if (BooleanUtil.isFalse(isCompiled)) {
|
||||
LiteFlowChainELBuilder.buildUnCompileChain(this);
|
||||
}
|
||||
public void setChainId(String chainId) {
|
||||
this.chainId = chainId;
|
||||
}
|
||||
|
||||
if (CollUtil.isEmpty(conditionList)) {
|
||||
throw new FlowSystemException("no conditionList in this chain[" + chainId + "]");
|
||||
}
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try {
|
||||
// 设置主ChainName
|
||||
slot.setChainId(chainId);
|
||||
// 执行主体Condition
|
||||
for (Condition condition : conditionList) {
|
||||
condition.setCurrChainId(chainId);
|
||||
condition.execute(slotIndex);
|
||||
}
|
||||
}
|
||||
catch (ChainEndException e) {
|
||||
// 这里单独catch ChainEndException是因为ChainEndException是用户自己setIsEnd抛出的异常
|
||||
// 是属于正常逻辑,所以会在FlowExecutor中判断。这里不作为异常处理
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
// 这里事先取到exception set到slot里,为了方便finally取到exception
|
||||
if (slot.isSubChain(chainId)) {
|
||||
slot.setSubException(chainId, e);
|
||||
}
|
||||
else {
|
||||
slot.setException(e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
// 执行chain的主方法
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
if (BooleanUtil.isFalse(isCompiled)) {
|
||||
LiteFlowChainELBuilder.buildUnCompileChain(this);
|
||||
}
|
||||
|
||||
public void executeRoute(Integer slotIndex) throws Exception {
|
||||
if (routeItem == null) {
|
||||
throw new FlowSystemException("no route condition or node in this chain[" + chainId + "]");
|
||||
}
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try {
|
||||
// 设置主ChainName
|
||||
slot.setChainId(chainId);
|
||||
if (CollUtil.isEmpty(conditionList)) {
|
||||
throw new FlowSystemException("no conditionList in this chain[" + chainId + "]");
|
||||
}
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try {
|
||||
// 设置主ChainName
|
||||
slot.setChainId(chainId);
|
||||
// 执行主体Condition
|
||||
for (Condition condition : conditionList) {
|
||||
condition.setCurrChainId(chainId);
|
||||
condition.execute(slotIndex);
|
||||
}
|
||||
} catch (ChainEndException e) {
|
||||
// 这里单独catch ChainEndException是因为ChainEndException是用户自己setIsEnd抛出的异常
|
||||
// 是属于正常逻辑,所以会在FlowExecutor中判断。这里不作为异常处理
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// 这里事先取到exception set到slot里,为了方便finally取到exception
|
||||
if (slot.isSubChain(chainId)) {
|
||||
slot.setSubException(chainId, e);
|
||||
} else {
|
||||
slot.setException(e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// 执行决策路由
|
||||
routeItem.setCurrChainId(chainId);
|
||||
routeItem.execute(slotIndex);
|
||||
public void executeRoute(Integer slotIndex) throws Exception {
|
||||
if (routeItem == null) {
|
||||
throw new FlowSystemException("no route condition or node in this chain[" + chainId + "]");
|
||||
}
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try {
|
||||
// 设置主ChainName
|
||||
slot.setChainId(chainId);
|
||||
|
||||
boolean routeResult = routeItem.getItemResultMetaValue(slotIndex);
|
||||
// 执行决策路由
|
||||
routeItem.setCurrChainId(chainId);
|
||||
routeItem.execute(slotIndex);
|
||||
|
||||
slot.setRouteResult(routeResult);
|
||||
}
|
||||
catch (ChainEndException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
slot.setException(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
boolean routeResult = routeItem.getItemResultMetaValue(slotIndex);
|
||||
|
||||
@Override
|
||||
public ExecuteableTypeEnum getExecuteType() {
|
||||
return ExecuteableTypeEnum.CHAIN;
|
||||
}
|
||||
slot.setRouteResult(routeResult);
|
||||
} catch (ChainEndException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
slot.setException(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(String id) {
|
||||
this.chainId = id;
|
||||
}
|
||||
@Override
|
||||
public ExecuteableTypeEnum getExecuteType() {
|
||||
return ExecuteableTypeEnum.CHAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return chainId;
|
||||
}
|
||||
@Override
|
||||
public void setId(String id) {
|
||||
this.chainId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTag(String tag) {
|
||||
//do nothing
|
||||
}
|
||||
@Override
|
||||
public String getId() {
|
||||
return chainId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTag() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void setTag(String tag) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
public Executable getRouteItem() {
|
||||
return routeItem;
|
||||
}
|
||||
@Override
|
||||
public String getTag() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setRouteItem(Executable routeItem) {
|
||||
this.routeItem = routeItem;
|
||||
}
|
||||
public Executable getRouteItem() {
|
||||
return routeItem;
|
||||
}
|
||||
|
||||
public String getEl() {
|
||||
return el;
|
||||
}
|
||||
public void setRouteItem(Executable routeItem) {
|
||||
this.routeItem = routeItem;
|
||||
}
|
||||
|
||||
public void setEl(String el) {
|
||||
this.el = el;
|
||||
}
|
||||
public String getEl() {
|
||||
return el;
|
||||
}
|
||||
|
||||
public boolean isCompiled() {
|
||||
return isCompiled;
|
||||
}
|
||||
public void setEl(String el) {
|
||||
this.el = el;
|
||||
}
|
||||
|
||||
public void setCompiled(boolean compiled) {
|
||||
isCompiled = compiled;
|
||||
}
|
||||
public boolean isCompiled() {
|
||||
return isCompiled;
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
public void setCompiled(boolean compiled) {
|
||||
isCompiled = compiled;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
public String getChainSha256() {
|
||||
return chainSha256;
|
||||
}
|
||||
|
||||
public void setChainSha256() {
|
||||
String ns = Optional.ofNullable(this.namespace).orElse("");
|
||||
this.chainSha256 = Sha256Util.sha256(chainId + ns + el);
|
||||
}
|
||||
|
||||
public boolean isExist() {
|
||||
if (StrUtil.isBlank(chainId) || StrUtil.isBlank(el)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String ns = Optional.ofNullable(this.namespace).orElse("");
|
||||
String elSha256 = Sha256Util.sha256(chainId + ns + el);
|
||||
for (Chain chainElement : FlowBus.getChainMap().values()) {
|
||||
String chainSha256Exist = chainElement.getChainSha256();
|
||||
if (Objects.equals(chainSha256Exist, elSha256)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,29 @@ import java.util.List;
|
|||
*/
|
||||
public class NodeConvertHelper {
|
||||
|
||||
/*script节点的修改/添加*/
|
||||
public static void changeScriptNode(NodeSimpleVO nodeSimpleVO, String newValue) {
|
||||
// 有语言类型
|
||||
if (StrUtil.isNotBlank(nodeSimpleVO.getLanguage())) {
|
||||
LiteFlowNodeBuilder.createScriptNode()
|
||||
.setId(nodeSimpleVO.getNodeId())
|
||||
.setType(NodeTypeEnum.getEnumByCode(nodeSimpleVO.getType()))
|
||||
.setName(nodeSimpleVO.getName())
|
||||
.setScript(newValue)
|
||||
.setLanguage(nodeSimpleVO.getLanguage())
|
||||
.build();
|
||||
}
|
||||
// 没有语言类型
|
||||
else {
|
||||
LiteFlowNodeBuilder.createScriptNode()
|
||||
.setId(nodeSimpleVO.getNodeId())
|
||||
.setType(NodeTypeEnum.getEnumByCode(nodeSimpleVO.getType()))
|
||||
.setName(nodeSimpleVO.getName())
|
||||
.setScript(newValue)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static NodeSimpleVO convert(String scriptKey){
|
||||
// 不需要去理解这串正则,就是一个匹配冒号的
|
||||
// 一定得是a:b,或是a:b:c...这种完整类型的字符串的
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package com.yomahub.liteflow.util;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* sha 256 工具类
|
||||
*
|
||||
* @author gaibu
|
||||
* @since 2.12.1
|
||||
*/
|
||||
public class Sha256Util {
|
||||
public static String sha256(String input) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] hash = digest.digest(input.getBytes());
|
||||
|
||||
// Convert byte array to hexadecimal string
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte b : hash) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
type (script|boolean_script|switch_script|for_script) #IMPLIED
|
||||
class CDATA #IMPLIED
|
||||
file CDATA #IMPLIED
|
||||
language (qlexpress|groovy|js|python|lua|aviator|java|kotlin) #IMPLIED
|
||||
language (qlexpress|groovy|js|python|lua|aviator|java) #IMPLIED
|
||||
enable (true|false) #IMPLIED
|
||||
>
|
||||
<!ATTLIST chain
|
||||
|
|
|
@ -16,7 +16,7 @@ public class SqlReadConstant {
|
|||
|
||||
public static final String SCRIPT_SQL_PATTERN = "SELECT * FROM {} WHERE {}=?";
|
||||
|
||||
public static final String CHAIN_XML_PATTERN = "<chain id=\"{}\" namespace=\"{}\"><route><![CDATA[{}]]></route><body><![CDATA[{}]]></body></chain>";
|
||||
public static final String CHAIN_XML_PATTERN = "<chain name=\"{}\"><![CDATA[{}]]></chain>";
|
||||
|
||||
public static final String NODE_XML_PATTERN = "<nodes>{}</nodes>";
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* sql 轮询任务抽象类,维护公共方法
|
||||
|
@ -21,11 +19,11 @@ import java.util.stream.Collectors;
|
|||
* @author houxinyu
|
||||
* @since 2.11.1
|
||||
*/
|
||||
public abstract class AbstractSqlReadPollTask<T> implements SqlReadPollTask<T> {
|
||||
public abstract class AbstractSqlReadPollTask implements SqlReadPollTask {
|
||||
private final Map<String/*唯一键*/, String/*data-xml的sha1值*/> DATA_SHA_MAP = new HashMap<>();
|
||||
private final SqlRead<T> read;
|
||||
private final SqlRead read;
|
||||
|
||||
public AbstractSqlReadPollTask(SqlRead<T> read) {
|
||||
public AbstractSqlReadPollTask(SqlRead read) {
|
||||
this.read = read;
|
||||
|
||||
if (!read.type().equals(type())) {
|
||||
|
@ -35,34 +33,35 @@ public abstract class AbstractSqlReadPollTask<T> implements SqlReadPollTask<T> {
|
|||
|
||||
@Override
|
||||
public void execute() {
|
||||
List<T> dataList = read.read();
|
||||
Map<String/*唯一键*/, String/*data-xml*/> newData = read.read();
|
||||
// 新增或者更新的元素
|
||||
List<T> saveElementList = new ArrayList<>();
|
||||
Map<String, String> saveElementMap = new HashMap<>();
|
||||
// 删除的元素
|
||||
List<String> deleteElementIds;
|
||||
List<String> deleteElementIds = new ArrayList<>();
|
||||
|
||||
for (T data : dataList) {
|
||||
String id = getKey(data);
|
||||
String newSHA = getNeedSha1Value(data);
|
||||
for (Map.Entry<String, String> entry : newData.entrySet()) {
|
||||
String id = entry.getKey();
|
||||
String element = entry.getValue();
|
||||
String newSHA = DigestUtil.sha1Hex(element);
|
||||
|
||||
// 新增
|
||||
// 如果封装的SHAMap中不存在该chain, 表示该元素为新增
|
||||
if (!DATA_SHA_MAP.containsKey(id)) {
|
||||
saveElementList.add(data);
|
||||
saveElementMap.put(id, element);
|
||||
|
||||
DATA_SHA_MAP.put(id, newSHA);
|
||||
}
|
||||
// 修改
|
||||
// SHA值发生变化,表示该元素的值已被修改,重新拉取变化的chain
|
||||
else if (!StrUtil.equals(newSHA, DATA_SHA_MAP.get(id))) {
|
||||
saveElementList.add(data);
|
||||
saveElementMap.put(id, element);
|
||||
|
||||
DATA_SHA_MAP.put(id, newSHA);
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> oldIdList = DATA_SHA_MAP.keySet(); // 旧的 id 列表
|
||||
Set<String> newIdList = dataList.stream().map(this::getKey).collect(Collectors.toSet()); // 新的 id 列表
|
||||
Set<String> newIdList = newData.keySet(); // 新的 id 列表
|
||||
// 计算单差集
|
||||
// 计算集合的单差集,即只返回【oldIdList】中有,但是【newIdList】中没有的元素,例如:
|
||||
// subtractToList([1,2,3,4],[2,3,4,5]) -》 [1]
|
||||
|
@ -72,8 +71,8 @@ public abstract class AbstractSqlReadPollTask<T> implements SqlReadPollTask<T> {
|
|||
DATA_SHA_MAP.remove(id);
|
||||
}
|
||||
|
||||
if (CollUtil.isNotEmpty(saveElementList)) {
|
||||
doSave(saveElementList);
|
||||
if (CollUtil.isNotEmpty(saveElementMap)) {
|
||||
doSave(saveElementMap);
|
||||
}
|
||||
|
||||
if (CollUtil.isNotEmpty(deleteElementIds)) {
|
||||
|
@ -82,34 +81,20 @@ public abstract class AbstractSqlReadPollTask<T> implements SqlReadPollTask<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void initData(List<T> dataList) {
|
||||
DATA_SHA_MAP.putAll(shaValue(dataList));
|
||||
public void initData(Map<String/*唯一键*/, String/*data-xml的数据*/> dataMap) {
|
||||
DATA_SHA_MAP.putAll(shaMapValue(dataMap));
|
||||
}
|
||||
|
||||
public abstract void doSave(List<T> saveElementList);
|
||||
public abstract void doSave(Map<String, String> saveElementMap);
|
||||
|
||||
public abstract void doDelete(List<String> deleteElementId);
|
||||
|
||||
private Map<String/*唯一键*/, String/*data-xml的sha1值*/> shaValue(List<T> dataList) {
|
||||
private Map<String/*唯一键*/, String/*data-xml的sha1值*/> shaMapValue(Map<String, String> dataMap) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
dataList.forEach(t -> result.put(getKey(t), DigestUtil.sha1Hex(getNeedSha1Value(t))));
|
||||
dataMap.forEach((k, v) -> {
|
||||
result.put(k, DigestUtil.sha1Hex(v));
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getNeedSha1Value(T data) {
|
||||
if (StrUtil.isBlank(getExtValue(data))) {
|
||||
return DigestUtil.sha1Hex(getValue(data));
|
||||
}else{
|
||||
return DigestUtil.sha1Hex(getValue(data) + "|||" + getExtValue(data));
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是chain,那就是返回chain的id,如果是script,那就返回script的id
|
||||
protected abstract String getKey(T t);
|
||||
|
||||
// 如果是chain,那就返回EL,如果是script,那就返回脚本数据
|
||||
protected abstract String getValue(T t);
|
||||
|
||||
// 如果是chain,那就返回route el,如果是script,这个不返回,因为script没有扩展value
|
||||
protected abstract String getExtValue(T t);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.yomahub.liteflow.parser.sql.polling;
|
|||
|
||||
import com.yomahub.liteflow.parser.constant.ReadType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -12,7 +11,7 @@ import java.util.Map;
|
|||
* @author houxinyu
|
||||
* @since 2.11.1
|
||||
*/
|
||||
public interface SqlReadPollTask<T> {
|
||||
public interface SqlReadPollTask {
|
||||
|
||||
/**
|
||||
* 执行
|
||||
|
@ -22,8 +21,9 @@ public interface SqlReadPollTask<T> {
|
|||
/**
|
||||
* 初始化数据
|
||||
*
|
||||
* @param dataMap 数据
|
||||
*/
|
||||
void initData(List<T> dataList);
|
||||
void initData(Map<String/*唯一键*/, String/*data-xml的数据*/> dataMap);
|
||||
|
||||
/**
|
||||
* 类型
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
package com.yomahub.liteflow.parser.sql.polling.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.parser.constant.ReadType;
|
||||
import com.yomahub.liteflow.parser.sql.polling.AbstractSqlReadPollTask;
|
||||
import com.yomahub.liteflow.parser.sql.read.SqlRead;
|
||||
import com.yomahub.liteflow.parser.sql.read.vo.ChainVO;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* chain 读取任务
|
||||
|
@ -19,20 +16,20 @@ import java.util.function.Consumer;
|
|||
* @author houxinyu
|
||||
* @since 2.11.1
|
||||
*/
|
||||
public class ChainReadPollTask extends AbstractSqlReadPollTask<ChainVO> {
|
||||
public class ChainReadPollTask extends AbstractSqlReadPollTask {
|
||||
|
||||
public ChainReadPollTask(SqlRead<ChainVO> read) {
|
||||
public ChainReadPollTask(SqlRead read) {
|
||||
super(read);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSave(List<ChainVO> saveElementList) {
|
||||
saveElementList.forEach(chainVO ->
|
||||
LiteFlowChainELBuilder.createChain().setChainId(chainVO.getChainId())
|
||||
.setRoute(chainVO.getRoute())
|
||||
.setNamespace(chainVO.getNamespace())
|
||||
.setEL(chainVO.getBody())
|
||||
.build());
|
||||
public void doSave(Map<String, String> saveElementMap) {
|
||||
for (Map.Entry<String, String> entry : saveElementMap.entrySet()) {
|
||||
String chainName = entry.getKey();
|
||||
String newData = entry.getValue();
|
||||
|
||||
LiteFlowChainELBuilder.createChain().setChainId(chainName).setEL(newData).build();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,21 +39,6 @@ public class ChainReadPollTask extends AbstractSqlReadPollTask<ChainVO> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getKey(ChainVO chainVO) {
|
||||
return chainVO.getChainId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getValue(ChainVO chainVO) {
|
||||
return chainVO.getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExtValue(ChainVO chainVO) {
|
||||
return chainVO.getRoute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadType type() {
|
||||
return ReadType.CHAIN;
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
package com.yomahub.liteflow.parser.sql.polling.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.parser.constant.ReadType;
|
||||
import com.yomahub.liteflow.parser.helper.NodeConvertHelper;
|
||||
import com.yomahub.liteflow.parser.sql.polling.AbstractSqlReadPollTask;
|
||||
import com.yomahub.liteflow.parser.sql.read.SqlRead;
|
||||
import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 脚本轮询任务
|
||||
|
@ -21,45 +16,32 @@ import java.util.function.Consumer;
|
|||
* @author houxinyu
|
||||
* @since 2.11.1
|
||||
*/
|
||||
public class ScriptReadPollTask extends AbstractSqlReadPollTask<ScriptVO> {
|
||||
public ScriptReadPollTask(SqlRead<ScriptVO> read) {
|
||||
public class ScriptReadPollTask extends AbstractSqlReadPollTask {
|
||||
public ScriptReadPollTask(SqlRead read) {
|
||||
super(read);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSave(List<ScriptVO> saveElementList) {
|
||||
saveElementList.forEach(scriptVO -> LiteFlowNodeBuilder.createScriptNode()
|
||||
.setId(scriptVO.getNodeId())
|
||||
.setType(NodeTypeEnum.getEnumByCode(scriptVO.getType()))
|
||||
.setName(scriptVO.getName())
|
||||
.setScript(scriptVO.getScript())
|
||||
.setLanguage(scriptVO.getLanguage())
|
||||
.build());
|
||||
public void doSave(Map<String, String> saveElementMap) {
|
||||
for (Map.Entry<String, String> entry : saveElementMap.entrySet()) {
|
||||
String scriptKey = entry.getKey();
|
||||
String newData = entry.getValue();
|
||||
|
||||
NodeConvertHelper.NodeSimpleVO scriptVO = NodeConvertHelper.convert(scriptKey);
|
||||
NodeConvertHelper.changeScriptNode(scriptVO, newData);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doDelete(List<String> deleteElementId) {
|
||||
for (String id : deleteElementId) {
|
||||
NodeConvertHelper.NodeSimpleVO scriptVO = NodeConvertHelper.convert(id);
|
||||
|
||||
// 删除script
|
||||
FlowBus.unloadScriptNode(id);
|
||||
FlowBus.unloadScriptNode(scriptVO.getNodeId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getKey(ScriptVO scriptVO) {
|
||||
return scriptVO.getNodeId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getValue(ScriptVO scriptVO) {
|
||||
return scriptVO.getScript();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExtValue(ScriptVO scriptVO) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadType type() {
|
||||
return ReadType.SCRIPT;
|
||||
|
|
|
@ -9,9 +9,7 @@ import com.yomahub.liteflow.parser.sql.util.LiteFlowJdbcUtil;
|
|||
import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -22,7 +20,7 @@ import java.util.Map;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.11.1
|
||||
*/
|
||||
public abstract class AbstractSqlRead<T> implements SqlRead<T> {
|
||||
public abstract class AbstractSqlRead implements SqlRead {
|
||||
public final SQLParserVO config;
|
||||
private static LFLog LOG = LFLoggerManager.getLogger(AbstractSqlRead.class);
|
||||
|
||||
|
@ -31,10 +29,10 @@ public abstract class AbstractSqlRead<T> implements SqlRead<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<T> read() {
|
||||
public Map<String/*规则唯一键*/, String/*规则内容*/> read() {
|
||||
// 如果不需要读取直接返回
|
||||
if (!needRead()) {
|
||||
return new ArrayList<>();
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
checkConfig();
|
||||
|
@ -42,7 +40,7 @@ public abstract class AbstractSqlRead<T> implements SqlRead<T> {
|
|||
// 如果允许,就打印 sql 语句
|
||||
logSqlIfEnable(sqlCmd);
|
||||
|
||||
List<T> result = new ArrayList<>();
|
||||
Map<String/*规则唯一键*/, String/*规则*/> result = new HashMap<>();
|
||||
Connection conn = null;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
|
@ -56,6 +54,9 @@ public abstract class AbstractSqlRead<T> implements SqlRead<T> {
|
|||
rs = stmt.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
String xml = buildXmlElement(rs);
|
||||
String uniqueKey = buildXmlElementUniqueKey(rs);
|
||||
|
||||
if (hasEnableFiled()){
|
||||
boolean enable = getEnableFiledValue(rs);
|
||||
// 如果停用,直接跳过
|
||||
|
@ -63,7 +64,7 @@ public abstract class AbstractSqlRead<T> implements SqlRead<T> {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
result.add(parse(rs));
|
||||
result.put(uniqueKey, xml);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
|
@ -75,8 +76,6 @@ public abstract class AbstractSqlRead<T> implements SqlRead<T> {
|
|||
return result;
|
||||
}
|
||||
|
||||
protected abstract T parse(ResultSet rs) throws SQLException;
|
||||
|
||||
/**
|
||||
* 是否包含启停字段
|
||||
*/
|
||||
|
@ -89,6 +88,10 @@ public abstract class AbstractSqlRead<T> implements SqlRead<T> {
|
|||
|
||||
public abstract String buildQuerySql();
|
||||
|
||||
public abstract String buildXmlElement(ResultSet rs) throws SQLException;
|
||||
|
||||
public abstract String buildXmlElementUniqueKey(ResultSet rs) throws SQLException;
|
||||
|
||||
public abstract void checkConfig();
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.yomahub.liteflow.parser.sql.read;
|
|||
|
||||
import com.yomahub.liteflow.parser.constant.ReadType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -12,14 +11,14 @@ import java.util.Map;
|
|||
* @author houxinyu
|
||||
* @since 2.11.1
|
||||
*/
|
||||
public interface SqlRead<T> {
|
||||
public interface SqlRead {
|
||||
|
||||
/**
|
||||
* 读取
|
||||
*
|
||||
* @return 返回读取到的数据
|
||||
*/
|
||||
List<T> read();
|
||||
Map<String/*规则唯一键*/, String/*规则内容*/> read();
|
||||
|
||||
/**
|
||||
* 类型
|
||||
|
|
|
@ -19,30 +19,28 @@ import java.util.Map;
|
|||
* @since 2.11.1
|
||||
*/
|
||||
public class SqlReadFactory {
|
||||
private static final Map<ReadType, SqlRead<?>> READ_MAP = new HashMap<>();
|
||||
private static final Map<ReadType, SqlReadPollTask<?>> POLL_TASK_MAP = new HashMap<>();
|
||||
private static final Map<ReadType, SqlRead> READ_MAP = new HashMap<>();
|
||||
private static final Map<ReadType, SqlReadPollTask> POLL_TASK_MAP = new HashMap<>();
|
||||
|
||||
public static void registerRead(SQLParserVO config) {
|
||||
READ_MAP.put(ReadType.CHAIN, new ChainRead(config));
|
||||
READ_MAP.put(ReadType.SCRIPT, new ScriptRead(config));
|
||||
READ_MAP.putIfAbsent(ReadType.CHAIN, new ChainRead(config));
|
||||
READ_MAP.putIfAbsent(ReadType.SCRIPT, new ScriptRead(config));
|
||||
}
|
||||
|
||||
public static void registerSqlReadPollTask(ReadType readType) {
|
||||
SqlRead<?> sqlRead = getSqlRead(readType);
|
||||
SqlRead sqlRead = getSqlRead(readType);
|
||||
if (ReadType.CHAIN.equals(readType)) {
|
||||
POLL_TASK_MAP.put(ReadType.CHAIN, new ChainReadPollTask((ChainRead)sqlRead));
|
||||
POLL_TASK_MAP.putIfAbsent(ReadType.CHAIN, new ChainReadPollTask(sqlRead));
|
||||
} else if (ReadType.SCRIPT.equals(readType)) {
|
||||
POLL_TASK_MAP.put(ReadType.SCRIPT, new ScriptReadPollTask((ScriptRead)sqlRead));
|
||||
POLL_TASK_MAP.putIfAbsent(ReadType.SCRIPT, new ScriptReadPollTask(sqlRead));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> SqlRead<T> getSqlRead(ReadType readType) {
|
||||
return (SqlRead<T>)READ_MAP.get(readType);
|
||||
public static SqlRead getSqlRead(ReadType readType) {
|
||||
return READ_MAP.get(readType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> SqlReadPollTask<T> getSqlReadPollTask(ReadType readType) {
|
||||
return (SqlReadPollTask<T>)POLL_TASK_MAP.get(readType);
|
||||
public static SqlReadPollTask getSqlReadPollTask(ReadType readType) {
|
||||
return POLL_TASK_MAP.get(readType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import com.yomahub.liteflow.parser.constant.ReadType;
|
|||
import com.yomahub.liteflow.parser.constant.SqlReadConstant;
|
||||
import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
|
||||
import com.yomahub.liteflow.parser.sql.read.AbstractSqlRead;
|
||||
import com.yomahub.liteflow.parser.sql.read.vo.ChainVO;
|
||||
import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
@ -18,26 +17,12 @@ import java.sql.SQLException;
|
|||
* @author houxinyu
|
||||
* @since 2.11.1
|
||||
*/
|
||||
public class ChainRead extends AbstractSqlRead<ChainVO> {
|
||||
public class ChainRead extends AbstractSqlRead {
|
||||
|
||||
public ChainRead(SQLParserVO config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChainVO parse(ResultSet rs) throws SQLException {
|
||||
ChainVO chainVO = new ChainVO();
|
||||
chainVO.setChainId(getStringFromRsWithCheck(rs, super.config.getChainNameField()));
|
||||
chainVO.setBody(getStringFromRsWithCheck(rs, super.config.getElDataField()));
|
||||
if (StrUtil.isNotBlank(super.config.getNamespaceField())){
|
||||
chainVO.setNamespace(getStringFromRs(rs, super.config.getNamespaceField()));
|
||||
}
|
||||
if (StrUtil.isNotBlank(super.config.getRouteField())){
|
||||
chainVO.setRoute(getStringFromRs(rs, super.config.getRouteField()));
|
||||
}
|
||||
return chainVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnableFiled() {
|
||||
String chainEnableField = super.config.getChainEnableField();
|
||||
|
@ -85,6 +70,20 @@ public class ChainRead extends AbstractSqlRead<ChainVO> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildXmlElement(ResultSet rs) throws SQLException {
|
||||
String elDataField = super.config.getElDataField();
|
||||
|
||||
return getStringFromRs(rs, elDataField);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildXmlElementUniqueKey(ResultSet rs) throws SQLException {
|
||||
String chainNameField = super.config.getChainNameField();
|
||||
|
||||
return getStringFromRsWithCheck(rs, chainNameField);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadType type() {
|
||||
return ReadType.CHAIN;
|
||||
|
|
|
@ -8,7 +8,6 @@ import com.yomahub.liteflow.parser.constant.ReadType;
|
|||
import com.yomahub.liteflow.parser.constant.SqlReadConstant;
|
||||
import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
|
||||
import com.yomahub.liteflow.parser.sql.read.AbstractSqlRead;
|
||||
import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO;
|
||||
import com.yomahub.liteflow.parser.sql.util.LiteFlowJdbcUtil;
|
||||
import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
|
||||
|
||||
|
@ -25,23 +24,12 @@ import java.util.Objects;
|
|||
* @author houxinyu
|
||||
* @since 2.11.1
|
||||
*/
|
||||
public class ScriptRead extends AbstractSqlRead<ScriptVO> {
|
||||
public class ScriptRead extends AbstractSqlRead {
|
||||
|
||||
public ScriptRead(SQLParserVO config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptVO parse(ResultSet rs) throws SQLException {
|
||||
ScriptVO scriptVO = new ScriptVO();
|
||||
scriptVO.setNodeId(getStringFromRsWithCheck(rs, super.config.getScriptIdField()));
|
||||
scriptVO.setName(getStringFromRs(rs, super.config.getScriptNameField()));
|
||||
scriptVO.setType(getStringFromRsWithCheck(rs, super.config.getScriptTypeField()));
|
||||
scriptVO.setLanguage(getStringFromRs(rs, super.config.getScriptLanguageField()));
|
||||
scriptVO.setScript(getStringFromRsWithCheck(rs, super.config.getScriptDataField()));
|
||||
return scriptVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnableFiled() {
|
||||
String scriptEnableField = super.config.getScriptEnableField();
|
||||
|
@ -92,6 +80,46 @@ public class ScriptRead extends AbstractSqlRead<ScriptVO> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildXmlElement(ResultSet rs) throws SQLException {
|
||||
String scriptDataField = super.config.getScriptDataField();
|
||||
|
||||
return getStringFromRs(rs, scriptDataField);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildXmlElementUniqueKey(ResultSet rs) throws SQLException {
|
||||
String scriptIdField = super.config.getScriptIdField();
|
||||
String scriptNameField = super.config.getScriptNameField();
|
||||
String scriptTypeField = super.config.getScriptTypeField();
|
||||
String scriptLanguageField = super.config.getScriptLanguageField();
|
||||
|
||||
String id = getStringFromRsWithCheck(rs, scriptIdField);
|
||||
String name = getStringFromRsWithCheck(rs, scriptNameField);
|
||||
String type = getStringFromRsWithCheck(rs, scriptTypeField);
|
||||
String language = withLanguage() ? getStringFromRs(rs, scriptLanguageField) : null;
|
||||
|
||||
NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type);
|
||||
if (Objects.isNull(nodeTypeEnum)) {
|
||||
throw new ELSQLException(StrUtil.format("Invalid type value[{}]", type));
|
||||
}
|
||||
|
||||
if (!nodeTypeEnum.isScript()) {
|
||||
throw new ELSQLException(StrUtil.format("The type value[{}] is not a script type", type));
|
||||
}
|
||||
|
||||
if (withLanguage() && !ScriptTypeEnum.checkScriptType(language)) {
|
||||
throw new ELSQLException(StrUtil.format("The language value[{}] is invalid", language));
|
||||
}
|
||||
List<String> keys = CollUtil.newArrayList(id, type, name);
|
||||
if (StrUtil.isNotBlank(language)) {
|
||||
keys.add(language);
|
||||
}
|
||||
|
||||
return StrUtil.join(StrUtil.COLON, keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needRead() {
|
||||
if (StrUtil.isBlank(super.config.getScriptTableName())) {
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
package com.yomahub.liteflow.parser.sql.read.vo;
|
||||
|
||||
public class ChainVO {
|
||||
|
||||
private String chainId;
|
||||
|
||||
private String route;
|
||||
|
||||
private String namespace;
|
||||
|
||||
private String body;
|
||||
|
||||
public String getChainId() {
|
||||
return chainId;
|
||||
}
|
||||
|
||||
public void setChainId(String chainId) {
|
||||
this.chainId = chainId;
|
||||
}
|
||||
|
||||
public String getRoute() {
|
||||
return route;
|
||||
}
|
||||
|
||||
public void setRoute(String route) {
|
||||
this.route = route;
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
package com.yomahub.liteflow.parser.sql.read.vo;
|
||||
|
||||
public class ScriptVO {
|
||||
|
||||
private String nodeId;
|
||||
|
||||
private String type;
|
||||
|
||||
private String name;
|
||||
|
||||
private String language;
|
||||
|
||||
private Boolean enable;
|
||||
|
||||
private String script;
|
||||
|
||||
public String getNodeId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
public void setNodeId(String nodeId) {
|
||||
this.nodeId = nodeId;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public Boolean getEnable() {
|
||||
return enable;
|
||||
}
|
||||
|
||||
public void setEnable(Boolean enable) {
|
||||
this.enable = enable;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return script;
|
||||
}
|
||||
|
||||
public void setScript(String script) {
|
||||
this.script = script;
|
||||
}
|
||||
}
|
|
@ -11,12 +11,9 @@ import com.yomahub.liteflow.parser.constant.ReadType;
|
|||
|
||||
import com.yomahub.liteflow.parser.helper.NodeConvertHelper;
|
||||
import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
|
||||
import com.yomahub.liteflow.parser.sql.polling.SqlReadPollTask;
|
||||
import com.yomahub.liteflow.parser.sql.read.AbstractSqlRead;
|
||||
import com.yomahub.liteflow.parser.sql.read.SqlRead;
|
||||
import com.yomahub.liteflow.parser.sql.read.SqlReadFactory;
|
||||
import com.yomahub.liteflow.parser.sql.read.vo.ChainVO;
|
||||
import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO;
|
||||
import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
|
@ -90,30 +87,30 @@ public class JDBCHelper {
|
|||
* @return 数据内容
|
||||
*/
|
||||
public String getContent() {
|
||||
SqlRead<ChainVO> chainRead = SqlReadFactory.getSqlRead(ReadType.CHAIN);
|
||||
SqlRead<ScriptVO> scriptRead = SqlReadFactory.getSqlRead(ReadType.SCRIPT);
|
||||
SqlRead chainRead = SqlReadFactory.getSqlRead(ReadType.CHAIN);
|
||||
SqlRead scriptRead = SqlReadFactory.getSqlRead(ReadType.SCRIPT);
|
||||
|
||||
// 获取 chain 数据
|
||||
List<ChainVO> chainVOList = chainRead.read();
|
||||
Map<String, String> chainMap = chainRead.read();
|
||||
List<String> chainList = new ArrayList<>();
|
||||
|
||||
chainVOList.forEach(
|
||||
chainVO -> chainList.add(StrUtil.format(CHAIN_XML_PATTERN, XmlUtil.escape(chainVO.getChainId()), StrUtil.emptyIfNull(chainVO.getNamespace()), StrUtil.emptyIfNull(chainVO.getRoute()), chainVO.getBody()))
|
||||
);
|
||||
|
||||
chainMap.entrySet().stream()
|
||||
.filter(entry -> StrUtil.isNotBlank(entry.getValue()))
|
||||
.forEach(
|
||||
entry -> chainList.add(StrUtil.format(CHAIN_XML_PATTERN, XmlUtil.escape(entry.getKey()), entry.getValue()))
|
||||
);
|
||||
|
||||
String chainsContent = CollUtil.join(chainList, StrUtil.EMPTY);
|
||||
|
||||
// 获取脚本数据
|
||||
List<ScriptVO> scriptVOList = scriptRead.read();
|
||||
Map<String, String> scriptMap = scriptRead.read();
|
||||
List<String> scriptList = new ArrayList<>();
|
||||
|
||||
scriptVOList.forEach(scriptVO -> {
|
||||
scriptMap.forEach((scriptKey, elData) -> {
|
||||
NodeConvertHelper.NodeSimpleVO scriptVO = NodeConvertHelper.convert(scriptKey);
|
||||
String id = scriptVO.getNodeId();
|
||||
String name = scriptVO.getName();
|
||||
String type = scriptVO.getType();
|
||||
String language = scriptVO.getLanguage();
|
||||
String elData = scriptVO.getScript();
|
||||
|
||||
if (StringUtils.isNotBlank(scriptVO.getLanguage())) {
|
||||
scriptList.add(StrUtil.format(NODE_ITEM_WITH_LANGUAGE_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, language, elData));
|
||||
|
@ -121,14 +118,11 @@ public class JDBCHelper {
|
|||
scriptList.add(StrUtil.format(NODE_ITEM_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, elData));
|
||||
}
|
||||
});
|
||||
|
||||
String nodesContent = StrUtil.format(NODE_XML_PATTERN, CollUtil.join(scriptList, StrUtil.EMPTY));
|
||||
|
||||
// 初始化轮询任务
|
||||
SqlReadPollTask<ChainVO> sqlReadPollTask4Chain = SqlReadFactory.getSqlReadPollTask(ReadType.CHAIN);
|
||||
sqlReadPollTask4Chain.initData(chainVOList);
|
||||
SqlReadPollTask<ScriptVO> sqlReadPollTask4Script = SqlReadFactory.getSqlReadPollTask(ReadType.SCRIPT);
|
||||
sqlReadPollTask4Script.initData(scriptVOList);
|
||||
SqlReadFactory.getSqlReadPollTask(ReadType.CHAIN).initData(chainMap);
|
||||
SqlReadFactory.getSqlReadPollTask(ReadType.SCRIPT).initData(scriptMap);
|
||||
return StrUtil.format(XML_PATTERN, nodesContent, chainsContent);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,16 +56,6 @@ public class SQLParserVO {
|
|||
*/
|
||||
private String elDataField = "el_data";
|
||||
|
||||
/**
|
||||
* 决策路由字段
|
||||
*/
|
||||
private String routeField;
|
||||
|
||||
/**
|
||||
* 命名空间字段
|
||||
*/
|
||||
private String namespaceField;
|
||||
|
||||
/**
|
||||
* 是否启动某一条chain
|
||||
*/
|
||||
|
@ -320,20 +310,4 @@ public class SQLParserVO {
|
|||
public boolean hasEnableField() {
|
||||
return StrUtil.isNotBlank(chainEnableField) || StrUtil.isNotBlank(scriptEnableField);
|
||||
}
|
||||
|
||||
public String getRouteField() {
|
||||
return routeField;
|
||||
}
|
||||
|
||||
public void setRouteField(String routeField) {
|
||||
this.routeField = routeField;
|
||||
}
|
||||
|
||||
public String getNamespaceField() {
|
||||
return namespaceField;
|
||||
}
|
||||
|
||||
public void setNamespaceField(String namespaceField) {
|
||||
this.namespaceField = namespaceField;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -65,7 +65,7 @@ public class AbsoluteConfigPathELDeclMultiSpringbootTest extends BaseTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isWindows")
|
||||
@DisabledIf("isWindows")
|
||||
public void testAbsPath() throws Exception{
|
||||
Assertions.assertTrue(() -> {
|
||||
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||
|
@ -80,7 +80,7 @@ public class AbsoluteConfigPathELDeclMultiSpringbootTest extends BaseTest {
|
|||
String osName = System.getProperty("os.name");
|
||||
if (osName.isEmpty()) return false;
|
||||
else {
|
||||
return osName.contains("Windows");
|
||||
return osName.contains("windows");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -67,7 +67,7 @@ public class AbsoluteConfigPathELDeclSpringbootTest extends BaseTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isWindows")
|
||||
@DisabledIf("isWindows")
|
||||
public void testAbsPath() throws Exception{
|
||||
Assertions.assertTrue(() -> {
|
||||
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||
|
@ -82,7 +82,7 @@ public class AbsoluteConfigPathELDeclSpringbootTest extends BaseTest {
|
|||
String osName = System.getProperty("os.name");
|
||||
if (osName.isEmpty()) return false;
|
||||
else {
|
||||
return osName.contains("Windows");
|
||||
return osName.contains("windows");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
|
|
|
@ -14,7 +14,7 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
@ -52,7 +52,7 @@ public class AbsoluteConfigPathTest extends BaseTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isWindows")
|
||||
@DisabledIf("isWindows")
|
||||
public void testAbsPath() throws Exception{
|
||||
Assertions.assertTrue(() -> {
|
||||
LiteflowConfig config = new LiteflowConfig();
|
||||
|
@ -67,7 +67,7 @@ public class AbsoluteConfigPathTest extends BaseTest {
|
|||
String osName = System.getProperty("os.name");
|
||||
if (osName.isEmpty()) return false;
|
||||
else {
|
||||
return osName.contains("Windows");
|
||||
return osName.contains("windows");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
|
|
|
@ -6,7 +6,9 @@ import com.yomahub.liteflow.core.FlowExecutor;
|
|||
import com.yomahub.liteflow.core.FlowExecutorHolder;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.ELParseException;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.builder.cmp.*;
|
||||
|
@ -175,4 +177,45 @@ public class BuilderTest extends BaseTest {
|
|||
Assertions.assertEquals("a1[组件A1]==>c2[组件C2]==>a2[组件A2]==>c1[组件C1]", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 测试 EL 表达式的覆盖
|
||||
@Test
|
||||
public void testBuilderElOver() throws Exception {
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("a1")
|
||||
.setName("组件A1")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(ACmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("a2")
|
||||
.setName("组件A2")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(ACmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("c1")
|
||||
.setName("组件C1")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(CCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("c2")
|
||||
.setName("组件C2")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(CCmp.class)
|
||||
.build();
|
||||
LiteFlowChainELBuilder.createChain().setChainName("chain1").setEL("THEN(a1,c2,a2,c1)").build();
|
||||
String sha256 = FlowBus.getChainMap().get("chain1").getChainSha256();
|
||||
|
||||
LiteFlowChainELBuilder.createChain().setChainId("chain1").setEL("THEN(a1,c2,a2,c1)").build();
|
||||
String sha256Same = FlowBus.getChainMap().get("chain1").getChainSha256();
|
||||
|
||||
Assertions.assertEquals(sha256, sha256Same);
|
||||
|
||||
LiteFlowChainELBuilder.createChain().setChainId("chain1").setEL("THEN(a1,c2,a2)").build();
|
||||
String chain1Sha256 = FlowBus.getChainMap().get("chain1").getChainSha256();
|
||||
|
||||
Assertions.assertNotEquals(sha256, chain1Sha256);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ public class FallbackTest extends BaseTest {
|
|||
LiteflowResponse response = flowExecutor.execute2Resp("concurrent2", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
String stepStr = response.getExecuteStepStrWithoutTime();
|
||||
Assertions.assertTrue("fb_comm_cmp==>fb_bool_cmp".equals(stepStr) || "fb_bool_cmp==>fb_comm_cmp".equals(stepStr));
|
||||
Assertions.assertTrue("fb_comm_cmp==>fb_bool_cmp".equals(stepStr) || "ifn2==>c".equals(stepStr));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.test.SolonJUnit5Extension;
|
||||
|
@ -58,7 +58,7 @@ public class AbsoluteConfigPathELSpringbootTest extends BaseTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isWindows")
|
||||
@DisabledIf("isWindows")
|
||||
public void testAbsTest() throws Exception {
|
||||
Assertions.assertTrue(() -> {
|
||||
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||
|
@ -73,7 +73,7 @@ public class AbsoluteConfigPathELSpringbootTest extends BaseTest {
|
|||
String osName = System.getProperty("os.name");
|
||||
if (osName.isEmpty()) return false;
|
||||
else {
|
||||
return osName.contains("Windows");
|
||||
return osName.contains("windows");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
|
@ -72,7 +72,7 @@ public class AbsoluteConfigPathELSpringbootTest extends BaseTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isWindows")
|
||||
@DisabledIf("isWindows")
|
||||
public void testAbsPath4() throws Exception{
|
||||
Assertions.assertTrue(() -> {
|
||||
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||
|
@ -87,7 +87,7 @@ public class AbsoluteConfigPathELSpringbootTest extends BaseTest {
|
|||
String osName = System.getProperty("os.name");
|
||||
if (osName.isEmpty()) return false;
|
||||
else {
|
||||
return osName.contains("Windows");
|
||||
return osName.contains("windows");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
@ -57,7 +57,7 @@ public class AbsoluteConfigPathELSpringTest extends BaseTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isWindows")
|
||||
@DisabledIf("isWindows")
|
||||
public void testAbsPath() throws Exception{
|
||||
Assertions.assertTrue(() -> {
|
||||
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||
|
@ -72,7 +72,7 @@ public class AbsoluteConfigPathELSpringTest extends BaseTest {
|
|||
String osName = System.getProperty("os.name");
|
||||
if (osName.isEmpty()) return false;
|
||||
else {
|
||||
return osName.contains("Windows");
|
||||
return osName.contains("windows");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
package com.yomahub.liteflow.test.sqlroute;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
|
||||
import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.util.JsonUtil;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @author tangkc
|
||||
* @since 2.9.0
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@TestPropertySource(value = "classpath:/application-route.properties")
|
||||
@SpringBootTest(classes = SQLRouteSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({ "com.yomahub.liteflow.test.sqlroute.cmp" })
|
||||
public class SQLRouteSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testRoute1() {
|
||||
List<LiteflowResponse> responseList = flowExecutor.executeRouteChain("ns", 15, DefaultContext.class);
|
||||
LiteflowResponse response1 = responseList.stream().filter(liteflowResponse -> liteflowResponse.getChainId().equals("r_chain1")).findFirst().orElse(null);
|
||||
Assertions.assertTrue(response1.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>c", response1.getExecuteStepStr());
|
||||
LiteflowResponse response2 = responseList.stream().filter(liteflowResponse -> liteflowResponse.getChainId().equals("r_chain2")).findFirst().orElse(null);
|
||||
Assertions.assertTrue(response2.isSuccess());
|
||||
Assertions.assertEquals("c==>b==>a", response2.getExecuteStepStr());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.sqlroute.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("a")
|
||||
public class ACmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.sqlroute.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("b")
|
||||
public class BCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.sqlroute.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("c")
|
||||
public class CCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package com.yomahub.liteflow.test.sqlroute.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeBooleanComponent;
|
||||
|
||||
@LiteflowComponent("r1")
|
||||
public class R1 extends NodeBooleanComponent {
|
||||
@Override
|
||||
public boolean processBoolean() throws Exception {
|
||||
int testInt = this.getRequestData();
|
||||
return testInt >= 10 && testInt <= 20;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package com.yomahub.liteflow.test.sqlroute.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeBooleanComponent;
|
||||
|
||||
@LiteflowComponent("r2")
|
||||
public class R2 extends NodeBooleanComponent {
|
||||
@Override
|
||||
public boolean processBoolean() throws Exception {
|
||||
int testInt = this.getRequestData();
|
||||
return testInt > 100;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
liteflow.rule-source-ext-data={\
|
||||
"url":"jdbc:h2:mem:test_db;MODE=MySQL",\
|
||||
"driverClassName":"org.h2.Driver",\
|
||||
"username":"root",\
|
||||
"password":"123456",\
|
||||
"applicationName":"demo",\
|
||||
"chainTableName":"EL_TABLE",\
|
||||
"chainApplicationNameField":"application_name",\
|
||||
"chainNameField":"chain_name",\
|
||||
"elDataField":"EL_DATA",\
|
||||
"routeField":"route",\
|
||||
"namespaceField":"namespace",\
|
||||
"scriptTableName":"script_node_table",\
|
||||
"scriptApplicationNameField":"application_name",\
|
||||
"scriptIdField":"script_node_id",\
|
||||
"scriptNameField":"script_node_name",\
|
||||
"scriptDataField":"script_node_data",\
|
||||
"scriptLanguageField":"script_language",\
|
||||
"scriptTypeField":"script_node_type"\
|
||||
}
|
||||
|
||||
spring.datasource.driver-class-name=org.h2.Driver
|
||||
spring.datasource.url=jdbc:h2:mem:test_db;MODE=MySQL
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=123456
|
||||
spring.datasource.schema=classpath:/sql/schema.sql
|
||||
spring.datasource.data=classpath:/sql/data.sql
|
||||
spring.datasource.platform=h2
|
|
@ -5,8 +5,6 @@ INSERT INTO EL_TABLE (APPLICATION_NAME,CHAIN_NAME,EL_DATA) values ('demo','chain
|
|||
INSERT INTO EL_TABLE (APPLICATION_NAME,CHAIN_NAME,EL_DATA) values ('demo','chain3','IF(x0, THEN(a, b));');
|
||||
INSERT INTO EL_TABLE (APPLICATION_NAME,CHAIN_NAME,EL_DATA) values ('demo','<chain3>','IF(x0, THEN(a, b));');
|
||||
INSERT INTO EL_TABLE (APPLICATION_NAME,CHAIN_NAME,EL_DATA) values ('demo','chain4','IF(x2, IF(x0, THEN(a, b)));');
|
||||
INSERT INTO EL_TABLE (APPLICATION_NAME,CHAIN_NAME,EL_DATA,ROUTE,NAMESPACE) values ('demo','r_chain1','THEN(a,b,c);','r1','ns');
|
||||
INSERT INTO EL_TABLE (APPLICATION_NAME,CHAIN_NAME,EL_DATA,ROUTE,NAMESPACE) values ('demo','r_chain2','THEN(c,b,a);','OR(r1,r2)','ns');
|
||||
|
||||
DELETE FROM SCRIPT_NODE_TABLE;
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@ create table IF NOT EXISTS `EL_TABLE`
|
|||
`application_name` varchar(32) NOT NULL,
|
||||
`chain_name` varchar(32) NOT NULL,
|
||||
`el_data` varchar(1024) NOT NULL,
|
||||
`route` varchar(1024),
|
||||
`namespace` varchar(32),
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
|
|
6
pom.xml
6
pom.xml
|
@ -39,7 +39,7 @@
|
|||
</scm>
|
||||
|
||||
<properties>
|
||||
<revision>2.12.1</revision>
|
||||
<revision>2.12.0</revision>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
|
@ -394,6 +394,10 @@
|
|||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<!-- 默认不使用 gpg ,如果需要使用请在打包命令中增加 -Dgpg.skip=false -->
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- version number -->
|
||||
<plugin>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 327 KiB |
Binary file not shown.
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 188 KiB |
Loading…
Reference in New Issue