feature #I6RF8Y EL表达式里支持并或非操作符

This commit is contained in:
everywhere.z 2023-03-29 19:09:22 +08:00
parent 44c8920ab7
commit d62611e90b
58 changed files with 775 additions and 204 deletions

View File

@ -16,7 +16,7 @@ import com.yomahub.liteflow.exception.FlowSystemException;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.flow.element.Chain;
import com.yomahub.liteflow.flow.element.Node;
import com.yomahub.liteflow.flow.element.condition.Condition;
import com.yomahub.liteflow.flow.element.Condition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -37,9 +37,9 @@ public class LiteFlowChainELBuilder {
private Chain chain;
/**
* //这是主体的Condition //声明这个变量而不是用chain.getConditionList的目的是为了辅助平滑加载
* //虽然FlowBus里面的map都是CopyOnWrite类型的但是在buildCondition的时候为了平滑加载所以不能事先把chain.getConditionList给设为空List
* //所以在这里做一个缓存等conditionList全部build完毕后再去一次性替换chain里面的conditionList
* 这是主体的Condition //声明这个变量而不是用chain.getConditionList的目的是为了辅助平滑加载
* 虽然FlowBus里面的map都是CopyOnWrite类型的但是在buildCondition的时候为了平滑加载所以不能事先把chain.getConditionList给设为空List
* 所以在这里做一个缓存等conditionList全部build完毕后再去一次性替换chain里面的conditionList
*/
private final List<Condition> conditionList;
@ -62,6 +62,9 @@ public class LiteFlowChainELBuilder {
EXPRESS_RUNNER.addFunction(ChainConstant.WHILE, new WhileOperator());
EXPRESS_RUNNER.addFunction(ChainConstant.ITERATOR, new IteratorOperator());
EXPRESS_RUNNER.addFunction(ChainConstant.CATCH, new CatchOperator());
EXPRESS_RUNNER.addFunction(ChainConstant.AND, new AndOperator());
EXPRESS_RUNNER.addFunction(ChainConstant.OR, new OrOperator());
EXPRESS_RUNNER.addFunction(ChainConstant.NOT, new NotOperator());
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELSE, Object.class, new ElseOperator());
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELIF, Object.class, new ElifOperator());
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO, Object.class, new ToOperator());
@ -139,18 +142,6 @@ public class LiteFlowChainELBuilder {
// 这里无论多复杂的外面必定有一个最外层的Condition所以这里只有一个内部可以嵌套很多层这点和以前的不太一样
Condition condition = (Condition) EXPRESS_RUNNER.execute(elStr, context, errorList, true, true);
// 从condition的第一层嵌套结构里拿出Pre和Finally节点
// 为什么只寻找第一层而不往下寻找了呢
// 因为这是一个规范如果在后面的层级中出现pre和finally语义上也不好理解所以pre和finally只能定义在第一层
// 如果硬是要在后面定义则执行的时候会忽略相关代码已做了判断
/*
* for (Executable executable : condition.getExecutableList()) { if
* (executable instanceof PreCondition) {
* this.preConditionList.add((PreCondition) executable); } else if (executable
* instanceof FinallyCondition) {
* this.finallyConditionList.add((FinallyCondition) executable); } }
*/
// 把主要的condition加入
this.conditionList.add(condition);
return this;

View File

@ -0,0 +1,33 @@
package com.yomahub.liteflow.builder.el.operator;
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.condition.AndOrCondition;
import com.yomahub.liteflow.flow.element.condition.BooleanConditionTypeEnum;
/**
* EL表达式中AND关键字的操作
* 主要用于适用于产生布尔类型结果的表达式中比如IF(AND(a,b)),WHILE(AND(a,b))
*
* @author Bryan.Zhang
* @since 2.10.2
*/
public class AndOperator extends BaseOperator<AndOrCondition> {
@Override
public AndOrCondition build(Object[] objects) throws Exception {
OperatorHelper.checkObjectSizeGtTwo(objects);
AndOrCondition andOrCondition = new AndOrCondition();
andOrCondition.setBooleanConditionType(BooleanConditionTypeEnum.AND);
for (Object object : objects){
OperatorHelper.checkObjectMustBeBooleanItem(object);
Executable item = OperatorHelper.convert(object, Executable.class);
andOrCondition.addItem(item);
}
return andOrCondition;
}
}

View File

@ -5,6 +5,7 @@ import com.ql.util.express.exception.QLException;
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.Node;
import com.yomahub.liteflow.flow.element.condition.LoopCondition;
@ -25,13 +26,9 @@ public class BreakOperator extends BaseOperator<LoopCondition> {
LoopCondition condition = OperatorHelper.convert(objects[0], LoopCondition.class, errorMsg);
// 获得需要执行的可执行表达式
Node breakNode = OperatorHelper.convert(objects[1], Node.class);
if (ListUtil.toList(NodeTypeEnum.BREAK, NodeTypeEnum.BREAK_SCRIPT).contains(breakNode.getType())) {
condition.setBreakNode(breakNode);
}
else {
throw new QLException("The parameter must be node-break item");
}
Executable breakItem = OperatorHelper.convert(objects[1], Node.class);
OperatorHelper.checkObjectMustBeBooleanItem(breakItem);
condition.setBreakItem(breakItem);
return condition;
}

View File

@ -5,7 +5,7 @@ import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.condition.CatchCondition;
import com.yomahub.liteflow.flow.element.condition.Condition;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.element.condition.LoopCondition;
/**

View File

@ -25,17 +25,15 @@ public class ElifOperator extends BaseOperator<IfCondition> {
IfCondition ifCondition = OperatorHelper.convert(objects[0], IfCondition.class);
// 解析第一个参数
Node ifNode = OperatorHelper.convert(objects[1], Node.class);
if (!ListUtil.toList(NodeTypeEnum.IF, NodeTypeEnum.IF_SCRIPT).contains(ifNode.getType())) {
throw new QLException("The first parameter must be If item");
}
Executable ifItem = OperatorHelper.convert(objects[1], Node.class);
OperatorHelper.checkObjectMustBeBooleanItem(ifItem);
// 解析第二个参数
Executable trueCaseExecutableItem = OperatorHelper.convert(objects[2], Executable.class);
// 构建一个内部的IfCondition
IfCondition ifConditionItem = new IfCondition();
ifConditionItem.setIfNode(ifNode);
ifConditionItem.setIfItem(ifItem);
ifConditionItem.setTrueCaseExecutableItem(trueCaseExecutableItem);
// 因为可能会有多个ELIF所以每一次拿到的caller总是最开始大的if需要遍历到没有falseCaseExecutable的地方

View File

@ -2,7 +2,7 @@ package com.yomahub.liteflow.builder.el.operator;
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
import com.yomahub.liteflow.flow.element.condition.Condition;
import com.yomahub.liteflow.flow.element.Condition;
/**
* EL规则中的id的操作符,只有condition可加id

View File

@ -7,7 +7,9 @@ import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.Node;
import com.yomahub.liteflow.flow.element.condition.AndOrCondition;
import com.yomahub.liteflow.flow.element.condition.IfCondition;
import com.yomahub.liteflow.flow.element.condition.NotCondition;
/**
* EL规则中的IF的操作符
@ -22,10 +24,8 @@ public class IfOperator extends BaseOperator<IfCondition> {
OperatorHelper.checkObjectSizeEq(objects, 2, 3);
// 解析第一个参数
Node ifNode = OperatorHelper.convert(objects[0], Node.class);
if (!ListUtil.toList(NodeTypeEnum.IF, NodeTypeEnum.IF_SCRIPT).contains(ifNode.getType())) {
throw new QLException("The first parameter must be If item");
}
Executable ifItem = OperatorHelper.convert(objects[0], Executable.class);
OperatorHelper.checkObjectMustBeBooleanItem(ifItem);
// 解析第二个参数
Executable trueCaseExecutableItem = OperatorHelper.convert(objects[1], Executable.class);
@ -37,7 +37,7 @@ public class IfOperator extends BaseOperator<IfCondition> {
}
IfCondition ifCondition = new IfCondition();
ifCondition.setIfNode(ifNode);
ifCondition.setIfItem(ifItem);
ifCondition.setTrueCaseExecutableItem(trueCaseExecutableItem);
ifCondition.setFalseCaseExecutableItem(falseCaseExecutableItem);
return ifCondition;

View File

@ -20,7 +20,7 @@ public class NodeOperator extends BaseOperator<Node> {
@Override
public Node build(Object[] objects) throws Exception {
OperatorHelper.checkObjectSizeNeqOne(objects);
OperatorHelper.checkObjectSizeEqOne(objects);
String nodeId = OperatorHelper.convert(objects[0], String.class);

View File

@ -0,0 +1,31 @@
package com.yomahub.liteflow.builder.el.operator;
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.condition.AndOrCondition;
import com.yomahub.liteflow.flow.element.condition.BooleanConditionTypeEnum;
import com.yomahub.liteflow.flow.element.condition.NotCondition;
/**
* EL表达式中NOT关键字的操作表示非的操作
* 主要用于适用于产生布尔类型结果的表达式中比如IF(NOT(a)),WHILE(NOT(a))
*
* @author Bryan.Zhang
* @since 2.10.2
*/
public class NotOperator extends BaseOperator<NotCondition> {
@Override
public NotCondition build(Object[] objects) throws Exception {
OperatorHelper.checkObjectSizeEqOne(objects);
Object object = objects[0];
OperatorHelper.checkObjectMustBeBooleanItem(object);
Executable item = OperatorHelper.convert(object, Executable.class);
NotCondition notCondition = new NotCondition();
notCondition.setItem(item);
return notCondition;
}
}

View File

@ -0,0 +1,33 @@
package com.yomahub.liteflow.builder.el.operator;
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.condition.AndOrCondition;
import com.yomahub.liteflow.flow.element.condition.BooleanConditionTypeEnum;
/**
* EL表达式中OR关键字的操作
* 主要用于适用于产生布尔类型结果的表达式中比如IF(OR(a,b)),WHILE(OR(a,b))
*
* @author Bryan.Zhang
* @since 2.10.2
*/
public class OrOperator extends BaseOperator<AndOrCondition> {
@Override
public AndOrCondition build(Object[] objects) throws Exception {
OperatorHelper.checkObjectSizeGtTwo(objects);
AndOrCondition andOrCondition = new AndOrCondition();
andOrCondition.setBooleanConditionType(BooleanConditionTypeEnum.OR);
for (Object object : objects){
OperatorHelper.checkObjectMustBeBooleanItem(object);
Executable item = OperatorHelper.convert(object, Executable.class);
andOrCondition.addItem(item);
}
return andOrCondition;
}
}

View File

@ -18,7 +18,7 @@ public class SwitchOperator extends BaseOperator<SwitchCondition> {
@Override
public SwitchCondition build(Object[] objects) throws Exception {
OperatorHelper.checkObjectSizeNeqOne(objects);
OperatorHelper.checkObjectSizeEqOne(objects);
Node switchNode = OperatorHelper.convert(objects[0], Node.class);
if (!ListUtil.toList(NodeTypeEnum.SWITCH, NodeTypeEnum.SWITCH_SCRIPT).contains(switchNode.getType())) {

View File

@ -5,6 +5,7 @@ import com.ql.util.express.exception.QLException;
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.Node;
import com.yomahub.liteflow.flow.element.condition.WhileCondition;
@ -18,15 +19,13 @@ public class WhileOperator extends BaseOperator<WhileCondition> {
@Override
public WhileCondition build(Object[] objects) throws Exception {
OperatorHelper.checkObjectSizeEq(objects, 1);
OperatorHelper.checkObjectSizeEqOne(objects);
Node node = OperatorHelper.convert(objects[0], Node.class);
if (!ListUtil.toList(NodeTypeEnum.WHILE, NodeTypeEnum.WHILE_SCRIPT).contains(node.getType())) {
throw new QLException("The parameter must be while-node item");
}
Executable whileItem = OperatorHelper.convert(objects[0], Executable.class);
OperatorHelper.checkObjectMustBeBooleanItem(whileItem);
WhileCondition whileCondition = new WhileCondition();
whileCondition.setWhileNode(node);
whileCondition.setWhileItem(whileItem);
return whileCondition;
}

View File

@ -16,8 +16,7 @@ public abstract class BaseOperator<T extends Executable> extends Operator {
@Override
public T executeInner(Object[] objects) throws Exception {
try {
// 检查 node chain 是否已经注册
OperatorHelper.checkNodeAndChainExist(objects);
OperatorHelper.checkItemNotNull(objects);
return build(objects);
}
catch (QLException e) {

View File

@ -1,9 +1,13 @@
package com.yomahub.liteflow.builder.el.operator.base;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.ql.util.express.exception.QLException;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.exception.DataNotFoundException;
import com.yomahub.liteflow.flow.element.Node;
import com.yomahub.liteflow.flow.element.condition.AndOrCondition;
import com.yomahub.liteflow.flow.element.condition.NotCondition;
import java.util.Objects;
@ -15,28 +19,6 @@ import java.util.Objects;
*/
public class OperatorHelper {
/**
* 检查参数数量不等于1
* @param objects objects
* @throws QLException QLException
*/
public static void checkObjectSizeNeqOne(Object[] objects) throws QLException {
checkObjectSizeNeq(objects, 1);
}
/**
* 检查参数数量不等于 size
* @param objects objects
* @param size 参数数量
* @throws QLException QLException
*/
public static void checkObjectSizeNeq(Object[] objects, int size) throws QLException {
checkObjectSizeGtZero(objects);
if (objects.length != size) {
throw new QLException("parameter error");
}
}
/**
* 检查参数数量大于 0
* @param objects objects
@ -60,6 +42,15 @@ public class OperatorHelper {
}
}
/**
* 检查参数数量等于 1
* @param objects objects
* @throws QLException QLException
*/
public static void checkObjectSizeEqOne(Object[] objects) throws QLException {
checkObjectSizeEq(objects, 1);
}
/**
* 检查参数数量等于 2
* @param objects objects
@ -138,12 +129,7 @@ public class OperatorHelper {
throw new QLException(errorMsg);
}
/**
* 检查 node chain 是否已经注册
* @param objects objects
* @throws QLException QLException
*/
public static void checkNodeAndChainExist(Object[] objects) throws QLException {
public static void checkItemNotNull(Object[] objects) throws QLException {
for (Object object : objects) {
if (Objects.isNull(object)) {
throw new QLException(DataNotFoundException.MSG);
@ -151,4 +137,17 @@ public class OperatorHelper {
}
}
/**
* 所谓Boolean item指的是那些最终的结果值为布尔类型的Item
* 布尔类型的items有ifwhilebreak类型的Node以及AndOrCondition以及NotCondition
*/
public static void checkObjectMustBeBooleanItem(Object object) throws Exception{
if (!(object instanceof Node && ListUtil.toList(
NodeTypeEnum.IF, NodeTypeEnum.IF_SCRIPT,
NodeTypeEnum.WHILE, NodeTypeEnum.WHILE_SCRIPT,
NodeTypeEnum.BREAK, NodeTypeEnum.BREAK_SCRIPT).contains(((Node) object).getType())
|| object instanceof AndOrCondition || object instanceof NotCondition)) {
throw new QLException("The first parameter must be boolean type Node or boolean type condition");
}
}
}

View File

@ -75,4 +75,10 @@ public interface ChainConstant {
String CATCH = "CATCH";
String AND = "AND";
String OR = "OR";
String NOT = "NOT";
}

View File

@ -1,5 +1,6 @@
package com.yomahub.liteflow.core;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
@ -21,4 +22,11 @@ public abstract class NodeBreakComponent extends NodeComponent {
public abstract boolean processBreak() throws Exception;
@Override
@SuppressWarnings("unchecked")
public Boolean getItemResultMetaValue(Integer slotIndex) {
Class<?> originalClass = LiteFlowProxyUtil.getUserClass(this.getClass());
return DataBus.getSlot(slotIndex).getBreakResult(originalClass.getName());
}
}

View File

@ -377,4 +377,7 @@ public abstract class NodeComponent {
return FlowExecutorHolder.loadInstance().invoke2RespInAsync(chainId, param, this.getSlotIndex());
}
public <T> T getItemResultMetaValue(Integer slotIndex){
return null;
}
}

View File

@ -1,5 +1,6 @@
package com.yomahub.liteflow.core;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
@ -21,4 +22,11 @@ public abstract class NodeForComponent extends NodeComponent {
public abstract int processFor() throws Exception;
@Override
@SuppressWarnings("unchecked")
public Integer getItemResultMetaValue(Integer slotIndex) {
Class<?> originalClass = LiteFlowProxyUtil.getUserClass(this.getClass());
return DataBus.getSlot(slotIndex).getForResult(originalClass.getName());
}
}

View File

@ -1,5 +1,6 @@
package com.yomahub.liteflow.core;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
/**
@ -19,4 +20,10 @@ public abstract class NodeIfComponent extends NodeComponent {
public abstract boolean processIf() throws Exception;
@Override
@SuppressWarnings("unchecked")
public Boolean getItemResultMetaValue(Integer slotIndex) {
Class<?> originalClass = LiteFlowProxyUtil.getUserClass(this.getClass());
return DataBus.getSlot(slotIndex).getIfResult(originalClass.getName());
}
}

View File

@ -1,5 +1,6 @@
package com.yomahub.liteflow.core;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
@ -23,4 +24,11 @@ public abstract class NodeIteratorComponent extends NodeComponent {
public abstract Iterator<?> processIterator() throws Exception;
@Override
@SuppressWarnings("unchecked")
public Iterator<?> getItemResultMetaValue(Integer slotIndex) {
Class<?> originalClass = LiteFlowProxyUtil.getUserClass(this.getClass());
return DataBus.getSlot(slotIndex).getIteratorResult(originalClass.getName());
}
}

View File

@ -7,6 +7,7 @@
*/
package com.yomahub.liteflow.core;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
/**
@ -26,4 +27,11 @@ public abstract class NodeSwitchComponent extends NodeComponent {
// 用以返回路由节点的beanId
public abstract String processSwitch() throws Exception;
@Override
@SuppressWarnings("unchecked")
public String getItemResultMetaValue(Integer slotIndex) {
Class<?> originalClass = LiteFlowProxyUtil.getUserClass(this.getClass());
return DataBus.getSlot(slotIndex).getSwitchResult(originalClass.getName());
}
}

View File

@ -1,5 +1,6 @@
package com.yomahub.liteflow.core;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
@ -21,4 +22,11 @@ public abstract class NodeWhileComponent extends NodeComponent {
public abstract boolean processWhile() throws Exception;
@Override
@SuppressWarnings("unchecked")
public Boolean getItemResultMetaValue(Integer slotIndex) {
Class<?> originalClass = LiteFlowProxyUtil.getUserClass(this.getClass());
return DataBus.getSlot(slotIndex).getWhileResult(originalClass.getName());
}
}

View File

@ -5,9 +5,17 @@ package com.yomahub.liteflow.enums;
*/
public enum ConditionTypeEnum {
TYPE_THEN("then", "then"), TYPE_WHEN("when", "when"), TYPE_SWITCH("switch", "switch"),
TYPE_THEN("then", "then"),
TYPE_IF("if", "if"), TYPE_PRE("pre", "pre"), TYPE_FINALLY("finally", "finally"),
TYPE_WHEN("when", "when"),
TYPE_SWITCH("switch", "switch"),
TYPE_IF("if", "if"),
TYPE_PRE("pre", "pre"),
TYPE_FINALLY("finally", "finally"),
TYPE_FOR("for", "for"),
@ -15,7 +23,11 @@ public enum ConditionTypeEnum {
TYPE_ITERATOR("iterator", "iterator"),
TYPE_CATCH("catch", "catch");
TYPE_CATCH("catch", "catch"),
TYPE_AND_OR_OPT("and_or_opt", "and_or_opt"),
TYPE_NOT_OPT("not_opt", "not_opt");
private String type;

View File

@ -0,0 +1,25 @@
package com.yomahub.liteflow.exception;
public class AndOrConditionException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* 异常信息
*/
private String message;
public AndOrConditionException(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -14,7 +14,6 @@ import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
import com.yomahub.liteflow.enums.ExecuteTypeEnum;
import com.yomahub.liteflow.exception.FlowSystemException;
import com.yomahub.liteflow.flow.element.condition.Condition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;

View File

@ -5,7 +5,7 @@
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.flow.element.condition;
package com.yomahub.liteflow.flow.element;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
@ -14,6 +14,7 @@ import com.yomahub.liteflow.enums.ExecuteTypeEnum;
import com.yomahub.liteflow.exception.ChainEndException;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.flow.element.condition.ConditionKey;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
@ -65,7 +66,7 @@ public abstract class Condition implements Executable {
}
}
protected abstract void executeCondition(Integer slotIndex) throws Exception;
public abstract void executeCondition(Integer slotIndex) throws Exception;
@Override
public ExecuteTypeEnum getExecuteType() {

View File

@ -40,4 +40,8 @@ public interface Executable {
}
default <T> T getItemResultMetaValue(Integer slotIndex){
return null;
}
}

View File

@ -275,4 +275,8 @@ public class Node implements Executable, Cloneable {
this.language = language;
}
@Override
public <T> T getItemResultMetaValue(Integer slotIndex) {
return instance.getItemResultMetaValue(slotIndex);
}
}

View File

@ -0,0 +1,85 @@
package com.yomahub.liteflow.flow.element.condition;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.exception.AndOrConditionException;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
import java.util.List;
public class AndOrCondition extends Condition {
private BooleanConditionTypeEnum booleanConditionType;
@Override
public void executeCondition(Integer slotIndex) throws Exception {
List<Executable> itemList = this.getItem();
if (CollUtil.isEmpty(itemList)){
throw new AndOrConditionException("boolean item list is null");
}
boolean[] booleanArray = new boolean[itemList.size()];
for (int i = 0; i < itemList.size(); i++) {
Executable item = itemList.get(i);
item.setCurrChainId(this.getCurrChainId());
item.execute(slotIndex);
booleanArray[i] = item.getItemResultMetaValue(slotIndex);
}
BooleanConditionTypeEnum booleanConditionType = this.getBooleanConditionType();
Slot slot = DataBus.getSlot(slotIndex);
String resultKey = StrUtil.format("{}_{}",this.getClass().getName(),this.hashCode());
switch (booleanConditionType) {
case AND:
slot.setAndOrResult(resultKey, BooleanUtil.and(booleanArray));
break;
case OR:
slot.setAndOrResult(resultKey, BooleanUtil.or(booleanArray));
break;
default:
throw new AndOrConditionException("condition type must be 'AND' or 'OR'");
}
}
@Override
@SuppressWarnings("unchecked")
public Boolean getItemResultMetaValue(Integer slotIndex) {
Slot slot = DataBus.getSlot(slotIndex);
String resultKey = StrUtil.format("{}_{}",this.getClass().getName(),this.hashCode());
return slot.getAndOrResult(resultKey);
}
@Override
public ConditionTypeEnum getConditionType() {
return ConditionTypeEnum.TYPE_AND_OR_OPT;
}
public void addItem(Executable item){
this.addExecutable(ConditionKey.AND_OR_ITEM_KEY, item);
}
public List<Executable> getItem(){
return this.getExecutableList(ConditionKey.AND_OR_ITEM_KEY);
}
public BooleanConditionTypeEnum getBooleanConditionType() {
return booleanConditionType;
}
public void setBooleanConditionType(BooleanConditionTypeEnum booleanConditionType) {
this.booleanConditionType = booleanConditionType;
}
}

View File

@ -0,0 +1,13 @@
package com.yomahub.liteflow.flow.element.condition;
/**
* 结果为Boolean类型的类型
* @author Bryan.Zhang
* @since 2.10.2
*/
public enum BooleanConditionTypeEnum {
AND,
OR,
NOT
}

View File

@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.exception.CatchErrorException;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;

View File

@ -32,4 +32,8 @@ public interface ConditionKey {
String CATCH_KEY = "CATCH_KEY";
String AND_OR_ITEM_KEY = "AND_OR_ITEM";
String NOT_ITEM_KEY = "NOT_ITEM_KEY";
}

View File

@ -8,6 +8,7 @@
package com.yomahub.liteflow.flow.element.condition;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.element.Executable;
/**

View File

@ -36,16 +36,14 @@ public class ForCondition extends LoopCondition {
forNode.setCurrChainId(this.getCurrChainId());
forNode.execute(slotIndex);
// 这里可能会有spring代理过的bean所以拿到user原始的class
Class<?> originalForCountClass = LiteFlowProxyUtil.getUserClass(forNode.getInstance().getClass());
// 获得循环次数
int forCount = slot.getForResult(originalForCountClass.getName());
int forCount = forNode.getItemResultMetaValue(slotIndex);
// 获得要循环的可执行对象
Executable executableItem = this.getDoExecutor();
// 获取Break节点
Node breakNode = this.getBreakNode();
Executable breakItem = this.getBreakItem();
// 循环执行
for (int i = 0; i < forCount; i++) {
@ -54,12 +52,11 @@ public class ForCondition extends LoopCondition {
setLoopIndex(executableItem, i);
executableItem.execute(slotIndex);
// 如果break组件不为空则去执行
if (ObjectUtil.isNotNull(breakNode)) {
breakNode.setCurrChainId(this.getCurrChainId());
setLoopIndex(breakNode, i);
breakNode.execute(slotIndex);
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(breakNode.getInstance().getClass());
boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
if (ObjectUtil.isNotNull(breakItem)) {
breakItem.setCurrChainId(this.getCurrChainId());
setLoopIndex(breakItem, i);
breakItem.execute(slotIndex);
boolean isBreak = breakItem.getItemResultMetaValue(slotIndex);
if (isBreak) {
break;
}

View File

@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.exception.*;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.Node;
import com.yomahub.liteflow.slot.DataBus;
@ -22,66 +23,62 @@ public class IfCondition extends Condition {
@Override
public void executeCondition(Integer slotIndex) throws Exception {
if (ListUtil.toList(NodeTypeEnum.IF, NodeTypeEnum.IF_SCRIPT).contains(getIfNode().getType())) {
// 先去判断isAccess方法如果isAccess方法都返回false整个IF表达式不执行
if (!this.getIfNode().isAccess(slotIndex)) {
return;
Executable ifItem = this.getIfItem();
// 先去判断isAccess方法如果isAccess方法都返回false整个IF表达式不执行
if (!ifItem.isAccess(slotIndex)) {
return;
}
// 先执行IF节点
ifItem.setCurrChainId(this.getCurrChainId());
ifItem.execute(slotIndex);
// 拿到If执行过的结果
boolean ifResult = ifItem.getItemResultMetaValue(slotIndex);
Executable trueCaseExecutableItem = this.getTrueCaseExecutableItem();
Executable falseCaseExecutableItem = this.getFalseCaseExecutableItem();
Slot slot = DataBus.getSlot(slotIndex);
if (ifResult) {
// trueCaseExecutableItem这个不能为空否则执行什么呢
if (ObjectUtil.isNull(trueCaseExecutableItem)) {
String errorInfo = StrUtil.format("[{}]:no if-true node found for the component[{}]",
slot.getRequestId(), ifItem.getExecuteId());
throw new NoIfTrueNodeException(errorInfo);
}
// 先执行IF节点
this.getIfNode().setCurrChainId(this.getCurrChainId());
this.getIfNode().execute(slotIndex);
// trueCaseExecutableItem 不能为前置或者后置组件
if (trueCaseExecutableItem instanceof PreCondition
|| trueCaseExecutableItem instanceof FinallyCondition) {
String errorInfo = StrUtil.format(
"[{}]:if component[{}] error, if true node cannot be pre or finally", slot.getRequestId(),
ifItem.getExecuteId());
throw new IfTargetCannotBePreOrFinallyException(errorInfo);
}
Slot slot = DataBus.getSlot(slotIndex);
// 这里可能会有spring代理过的bean所以拿到user原始的class
Class<?> originalClass = LiteFlowProxyUtil.getUserClass(this.getIfNode().getInstance().getClass());
// 拿到If执行过的结果
boolean ifResult = slot.getIfResult(originalClass.getName());
Executable trueCaseExecutableItem = this.getTrueCaseExecutableItem();
Executable falseCaseExecutableItem = this.getFalseCaseExecutableItem();
if (ifResult) {
// trueCaseExecutableItem这个不能为空否则执行什么呢
if (ObjectUtil.isNull(trueCaseExecutableItem)) {
String errorInfo = StrUtil.format("[{}]:no if-true node found for the component[{}]",
slot.getRequestId(), this.getIfNode().getInstance().getDisplayName());
throw new NoIfTrueNodeException(errorInfo);
}
// trueCaseExecutableItem 不能为前置或者后置组件
if (trueCaseExecutableItem instanceof PreCondition
|| trueCaseExecutableItem instanceof FinallyCondition) {
// 执行trueCaseExecutableItem
trueCaseExecutableItem.setCurrChainId(this.getCurrChainId());
trueCaseExecutableItem.execute(slotIndex);
}
else {
// falseCaseExecutableItem可以为null但是不为null时就执行否的情况
if (ObjectUtil.isNotNull(falseCaseExecutableItem)) {
// falseCaseExecutableItem 不能为前置或者后置组件
if (falseCaseExecutableItem instanceof PreCondition
|| falseCaseExecutableItem instanceof FinallyCondition) {
String errorInfo = StrUtil.format(
"[{}]:if component[{}] error, if true node cannot be pre or finally", slot.getRequestId(),
this.getIfNode().getInstance().getDisplayName());
"[{}]:if component[{}] error, if true node cannot be pre or finally",
slot.getRequestId(), ifItem.getExecuteId());
throw new IfTargetCannotBePreOrFinallyException(errorInfo);
}
// 执行trueCaseExecutableItem
trueCaseExecutableItem.setCurrChainId(this.getCurrChainId());
trueCaseExecutableItem.execute(slotIndex);
// 执行falseCaseExecutableItem
falseCaseExecutableItem.setCurrChainId(this.getCurrChainId());
falseCaseExecutableItem.execute(slotIndex);
}
else {
// falseCaseExecutableItem可以为null但是不为null时就执行否的情况
if (ObjectUtil.isNotNull(falseCaseExecutableItem)) {
// falseCaseExecutableItem 不能为前置或者后置组件
if (falseCaseExecutableItem instanceof PreCondition
|| falseCaseExecutableItem instanceof FinallyCondition) {
String errorInfo = StrUtil.format(
"[{}]:if component[{}] error, if true node cannot be pre or finally",
slot.getRequestId(), this.getIfNode().getInstance().getDisplayName());
throw new IfTargetCannotBePreOrFinallyException(errorInfo);
}
// 执行falseCaseExecutableItem
falseCaseExecutableItem.setCurrChainId(this.getCurrChainId());
falseCaseExecutableItem.execute(slotIndex);
}
}
}
else {
throw new IfTypeErrorException("if instance must be NodeIfComponent");
}
}
@ -106,12 +103,11 @@ public class IfCondition extends Condition {
this.addExecutable(ConditionKey.IF_FALSE_CASE_KEY, falseCaseExecutableItem);
}
public void setIfNode(Node ifNode) {
public void setIfItem(Executable ifNode) {
this.addExecutable(ConditionKey.IF_KEY, ifNode);
}
public Node getIfNode() {
return (Node) this.getExecutableOne(ConditionKey.IF_KEY);
public Executable getIfItem() {
return this.getExecutableOne(ConditionKey.IF_KEY);
}
}

View File

@ -25,7 +25,7 @@ public class IteratorCondition extends LoopCondition {
}
// 先去判断isAccess方法如果isAccess方法都返回false整个ITERATOR表达式不执行
if (!this.getIteratorNode().isAccess(slotIndex)) {
if (!iteratorNode.isAccess(slotIndex)) {
return;
}
@ -33,16 +33,13 @@ public class IteratorCondition extends LoopCondition {
iteratorNode.setCurrChainId(this.getCurrChainId());
iteratorNode.execute(slotIndex);
// 这里可能会有spring代理过的bean所以拿到user原始的class
Class<?> originalForCountClass = LiteFlowProxyUtil.getUserClass(iteratorNode.getInstance().getClass());
// 获得迭代器
Iterator<?> it = slot.getIteratorResult(originalForCountClass.getName());
Iterator<?> it = iteratorNode.getItemResultMetaValue(slotIndex);
// 获得要循环的可执行对象
Executable executableItem = this.getDoExecutor();
// 获取Break节点
Node breakNode = this.getBreakNode();
Executable breakItem = this.getBreakItem();
int index = 0;
while (it.hasNext()) {
@ -56,13 +53,12 @@ public class IteratorCondition extends LoopCondition {
// 执行可执行对象
executableItem.execute(slotIndex);
// 如果break组件不为空则去执行
if (ObjectUtil.isNotNull(breakNode)) {
breakNode.setCurrChainId(this.getCurrChainId());
setLoopIndex(breakNode, index);
setCurrLoopObject(breakNode, itObj);
breakNode.execute(slotIndex);
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(breakNode.getInstance().getClass());
boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
if (ObjectUtil.isNotNull(breakItem)) {
breakItem.setCurrChainId(this.getCurrChainId());
setLoopIndex(breakItem, index);
setCurrLoopObject(breakItem, itObj);
breakItem.execute(slotIndex);
boolean isBreak = breakItem.getItemResultMetaValue(slotIndex);
if (isBreak) {
break;
}

View File

@ -1,13 +1,10 @@
package com.yomahub.liteflow.flow.element.condition;
import com.yomahub.liteflow.flow.element.Chain;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.Node;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* 循环Condition的抽象类 主要继承对象有ForCondition和WhileCondition
*
@ -16,11 +13,11 @@ import java.util.function.Consumer;
*/
public abstract class LoopCondition extends Condition {
protected Node getBreakNode() {
return (Node) this.getExecutableOne(ConditionKey.BREAK_KEY);
protected Executable getBreakItem() {
return this.getExecutableOne(ConditionKey.BREAK_KEY);
}
public void setBreakNode(Node breakNode) {
public void setBreakItem(Executable breakNode) {
this.addExecutable(ConditionKey.BREAK_KEY, breakNode);
}

View File

@ -0,0 +1,48 @@
package com.yomahub.liteflow.flow.element.condition;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
public class NotCondition extends Condition {
@Override
public void executeCondition(Integer slotIndex) throws Exception {
Executable item = this.getItem();
item.setCurrChainId(this.getCurrChainId());
item.execute(slotIndex);
boolean flag = item.getItemResultMetaValue(slotIndex);
Slot slot = DataBus.getSlot(slotIndex);
String resultKey = StrUtil.format("{}_{}",this.getClass().getName(),this.hashCode());
slot.setAndOrResult(resultKey, !flag);
}
@Override
@SuppressWarnings("unchecked")
public Boolean getItemResultMetaValue(Integer slotIndex) {
Slot slot = DataBus.getSlot(slotIndex);
String resultKey = StrUtil.format("{}_{}",this.getClass().getName(),this.hashCode());
return slot.getAndOrResult(resultKey);
}
@Override
public ConditionTypeEnum getConditionType() {
return ConditionTypeEnum.TYPE_NOT_OPT;
}
public void setItem(Executable item){
this.addExecutable(ConditionKey.NOT_ITEM_KEY, item);
}
public Executable getItem(){
return this.getExecutableOne(ConditionKey.NOT_ITEM_KEY);
}
}

View File

@ -8,6 +8,7 @@
package com.yomahub.liteflow.flow.element.condition;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.element.Executable;
/**

View File

@ -8,13 +8,13 @@ import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.exception.NoSwitchTargetNodeException;
import com.yomahub.liteflow.exception.SwitchTargetCannotBePreOrFinallyException;
import com.yomahub.liteflow.exception.SwitchTypeErrorException;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.Node;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
import java.util.ArrayList;
import java.util.List;
/**
@ -46,11 +46,10 @@ public class SwitchCondition extends Condition {
switchNode.setCurrChainId(this.getCurrChainId());
switchNode.execute(slotIndex);
// 根据switch节点执行出来的结果选择
// 拿到switch节点的结果
String targetId = switchNode.getItemResultMetaValue(slotIndex);
Slot slot = DataBus.getSlot(slotIndex);
// 这里可能会有spring代理过的bean所以拿到user原始的class
Class<?> originalClass = LiteFlowProxyUtil.getUserClass(switchNode.getInstance().getClass());
String targetId = slot.getSwitchResult(originalClass.getName());
Executable targetExecutor = null;
if (StrUtil.isNotBlank(targetId)) {

View File

@ -9,6 +9,7 @@ package com.yomahub.liteflow.flow.element.condition;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.exception.ChainEndException;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;

View File

@ -11,6 +11,7 @@ import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.common.LocalDefaultFlowConstant;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.exception.WhenExecuteException;
import com.yomahub.liteflow.flow.element.Condition;
import com.yomahub.liteflow.flow.parallel.CompletableFutureTimeout;
import com.yomahub.liteflow.flow.parallel.ParallelSupplier;
import com.yomahub.liteflow.flow.parallel.WhenFutureObj;

View File

@ -1,14 +1,9 @@
package com.yomahub.liteflow.flow.element.condition;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.exception.NoWhileNodeException;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.Node;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
/**
* 循环条件Condition
@ -20,15 +15,10 @@ public class WhileCondition extends LoopCondition {
@Override
public void executeCondition(Integer slotIndex) throws Exception {
Slot slot = DataBus.getSlot(slotIndex);
Node whileNode = this.getWhileNode();
if (ObjectUtil.isNull(whileNode)) {
String errorInfo = StrUtil.format("[{}]:no while-node found", slot.getRequestId());
throw new NoWhileNodeException(errorInfo);
}
Executable whileItem = this.getWhileItem();
// 先去判断isAccess方法如果isAccess方法都返回false整个WHILE表达式不执行
if (!this.getWhileNode().isAccess(slotIndex)) {
if (!whileItem.isAccess(slotIndex)) {
return;
}
@ -36,7 +26,7 @@ public class WhileCondition extends LoopCondition {
Executable executableItem = this.getDoExecutor();
// 获取Break节点
Node breakNode = this.getBreakNode();
Executable breakItem = this.getBreakItem();
// 循环执行
int index = 0;
@ -45,12 +35,11 @@ public class WhileCondition extends LoopCondition {
setLoopIndex(executableItem, index);
executableItem.execute(slotIndex);
// 如果break组件不为空则去执行
if (ObjectUtil.isNotNull(breakNode)) {
breakNode.setCurrChainId(this.getCurrChainId());
setLoopIndex(breakNode, index);
breakNode.execute(slotIndex);
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(breakNode.getInstance().getClass());
boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
if (ObjectUtil.isNotNull(breakItem)) {
breakItem.setCurrChainId(this.getCurrChainId());
setLoopIndex(breakItem, index);
breakItem.execute(slotIndex);
boolean isBreak = breakItem.getItemResultMetaValue(slotIndex);
if (isBreak) {
break;
}
@ -60,13 +49,12 @@ public class WhileCondition extends LoopCondition {
}
private boolean getWhileResult(Integer slotIndex) throws Exception {
Slot slot = DataBus.getSlot(slotIndex);
Node whileNode = this.getWhileNode();
Executable whileItem = this.getWhileItem();
// 执行while组件
whileNode.setCurrChainId(this.getCurrChainId());
whileNode.execute(slotIndex);
Class<?> originalWhileClass = LiteFlowProxyUtil.getUserClass(whileNode.getInstance().getClass());
return slot.getWhileResult(originalWhileClass.getName());
whileItem.setCurrChainId(this.getCurrChainId());
whileItem.execute(slotIndex);
return whileItem.getItemResultMetaValue(slotIndex);
}
@Override
@ -74,12 +62,12 @@ public class WhileCondition extends LoopCondition {
return ConditionTypeEnum.TYPE_WHILE;
}
public Node getWhileNode() {
return (Node) this.getExecutableOne(ConditionKey.WHILE_KEY);
public Executable getWhileItem() {
return this.getExecutableOne(ConditionKey.WHILE_KEY);
}
public void setWhileNode(Node whileNode) {
this.addExecutable(ConditionKey.WHILE_KEY, whileNode);
public void setWhileItem(Executable whileItem) {
this.addExecutable(ConditionKey.WHILE_KEY, whileItem);
}
}

View File

@ -17,20 +17,20 @@ public class ParallelSupplier implements Supplier<WhenFutureObj> {
private final Executable executableItem;
private final String currChainName;
private final String currChainId;
private final Integer slotIndex;
public ParallelSupplier(Executable executableItem, String currChainName, Integer slotIndex) {
public ParallelSupplier(Executable executableItem, String currChainId, Integer slotIndex) {
this.executableItem = executableItem;
this.currChainName = currChainName;
this.currChainId = currChainId;
this.slotIndex = slotIndex;
}
@Override
public WhenFutureObj get() {
try {
executableItem.setCurrChainId(currChainName);
executableItem.setCurrChainId(currChainId);
executableItem.execute(slotIndex);
return WhenFutureObj.success(executableItem.getExecuteId());
}

View File

@ -50,6 +50,10 @@ public class Slot {
private static final String IF_NODE_PREFIX = "_if_";
private static final String AND_OR_PREFIX = "_and_or_";
private static final String NOT_PREFIX = "_not_";
private static final String FOR_PREFIX = "_for_";
private static final String WHILE_PREFIX = "_while_";
@ -233,6 +237,22 @@ public class Slot {
return getThreadMetaData(IF_NODE_PREFIX + key);
}
public void setAndOrResult(String key, boolean result) {
putThreadMetaDataMap(AND_OR_PREFIX + key, result);
}
public boolean getAndOrResult(String key) {
return getThreadMetaData(AND_OR_PREFIX + key);
}
public void setNotResult(String key, boolean result) {
putThreadMetaDataMap(NOT_PREFIX + key, result);
}
public boolean getNotResult(String key) {
return getThreadMetaData(NOT_PREFIX + key);
}
public void setForResult(String key, int forCount) {
putThreadMetaDataMap(FOR_PREFIX + key, forCount);
}

View File

@ -0,0 +1,70 @@
package com.yomahub.liteflow.test.booleanOpt;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
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.junit4.SpringRunner;
import javax.annotation.Resource;
/**
* springboot环境EL常规的例子测试
*
* @author Bryan.Zhang
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/booleanOpt/application.properties")
@SpringBootTest(classes = BooleanOptELSpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({ "com.yomahub.liteflow.test.booleanOpt.cmp" })
public class BooleanOptELSpringbootTest extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
// IF情况下AND
@Test
public void testBooleanOpt1() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("x1==>x2==>x3==>b", response.getExecuteStepStr());
}
// IF情况下OR
@Test
public void testBooleanOpt2() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("x1==>x2==>x3==>a", response.getExecuteStepStr());
}
// IF情况下AND+NOT
@Test
public void testBooleanOpt3() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("x1==>x2==>x3==>a", response.getExecuteStepStr());
}
// IF情况下AND+OR+NOT混合复杂
@Test
public void testBooleanOpt4() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("x1==>x3==>x3==>x4==>a", response.getExecuteStepStr());
}
@Test
public void testBooleanOpt5() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("w1==>w2==>a==>bk==>w1==>w2==>a==>bk==>w1==>w2==>a==>bk==>w1==>w2==>a==>bk", response.getExecuteStepStr());
}
}

View File

@ -0,0 +1,21 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.booleanOpt.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!");
}
}

View File

@ -0,0 +1,21 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.booleanOpt.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!");
}
}

View File

@ -0,0 +1,13 @@
package com.yomahub.liteflow.test.booleanOpt.cmp;
import com.yomahub.liteflow.core.NodeBreakComponent;
import org.springframework.stereotype.Component;
@Component("bk")
public class BK extends NodeBreakComponent {
@Override
public boolean processBreak() throws Exception {
int index = this.getLoopIndex();
return index > 2;
}
}

View File

@ -0,0 +1,20 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.booleanOpt.cmp;
import com.yomahub.liteflow.core.NodeWhileComponent;
import org.springframework.stereotype.Component;
@Component("w1")
public class W1 extends NodeWhileComponent {
@Override
public boolean processWhile() throws Exception {
return true;
}
}

View File

@ -0,0 +1,20 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.booleanOpt.cmp;
import com.yomahub.liteflow.core.NodeWhileComponent;
import org.springframework.stereotype.Component;
@Component("w2")
public class W2 extends NodeWhileComponent {
@Override
public boolean processWhile() throws Exception {
return false;
}
}

View File

@ -0,0 +1,12 @@
package com.yomahub.liteflow.test.booleanOpt.cmp;
import com.yomahub.liteflow.core.NodeIfComponent;
import org.springframework.stereotype.Component;
@Component("x1")
public class X1 extends NodeIfComponent {
@Override
public boolean processIf() throws Exception {
return true;
}
}

View File

@ -0,0 +1,12 @@
package com.yomahub.liteflow.test.booleanOpt.cmp;
import com.yomahub.liteflow.core.NodeIfComponent;
import org.springframework.stereotype.Component;
@Component("x2")
public class X2 extends NodeIfComponent {
@Override
public boolean processIf() throws Exception {
return true;
}
}

View File

@ -0,0 +1,12 @@
package com.yomahub.liteflow.test.booleanOpt.cmp;
import com.yomahub.liteflow.core.NodeIfComponent;
import org.springframework.stereotype.Component;
@Component("x3")
public class X3 extends NodeIfComponent {
@Override
public boolean processIf() throws Exception {
return false;
}
}

View File

@ -0,0 +1,12 @@
package com.yomahub.liteflow.test.booleanOpt.cmp;
import com.yomahub.liteflow.core.NodeIfComponent;
import org.springframework.stereotype.Component;
@Component("x4")
public class X4 extends NodeIfComponent {
@Override
public boolean processIf() throws Exception {
return false;
}
}

View File

@ -30,7 +30,7 @@ public class MonitorFileELSpringbootTest extends BaseTest {
@Test
public void testMonitor() throws Exception {
String absolutePath = new ClassPathResource("classpath:/monitorFile/flow.el.xml").getAbsolutePath();
String absolutePath = new ClassPathResource("classpath:/monitorFile/flow.xml").getAbsolutePath();
String content = FileUtil.readUtf8String(absolutePath);
String newContent = content.replace("THEN(a, b, c);", "THEN(a, c, b);");
FileUtil.writeString(newContent, new File(absolutePath), CharsetUtil.CHARSET_UTF_8);

View File

@ -0,0 +1 @@
liteflow.rule-source=booleanOpt/flow.xml

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE flow PUBLIC "liteflow" "liteflow.dtd">
<flow>
<chain name="chain1">
IF(AND(x1, x2, x3), a, b);
</chain>
<chain name="chain2">
IF(OR(x1, x2, x3), a, b);
</chain>
<chain name="chain3">
IF(AND(x1, x2, NOT(x3)), a, b);
</chain>
<chain name="chain4">
IF(
OR(
AND(x1, x3), NOT(OR(x3, x4))
),
a, b
);
</chain>
<chain name="chain5">
WHILE(AND(w1, NOT(w2))).DO(a).BREAK(bk);
</chain>
</flow>