Compare commits

...

2 Commits

Author SHA1 Message Date
gaibu bc86356078 enhancement #I9FM3I chain 中增加一个指纹值 2024-05-17 22:50:32 +08:00
gaibu 33197922d6 enhancement #I9FM3I chain 中增加一个指纹值 2024-05-17 22:43:09 +08:00
4 changed files with 269 additions and 144 deletions

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}