Compare commits
2 Commits
master
...
issues/I9F
Author | SHA1 | Date |
---|---|---|
![]() |
bc86356078 | |
![]() |
33197922d6 |
|
@ -183,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)){
|
||||
|
@ -256,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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue