diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java index e8faff6a1..542974912 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java @@ -1,23 +1,19 @@ package com.yomahub.liteflow.builder; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.enums.NodeTypeEnum; import com.yomahub.liteflow.exception.NodeBuildException; import com.yomahub.liteflow.flow.FlowBus; import com.yomahub.liteflow.flow.element.Node; +import com.yomahub.liteflow.spi.holder.PathContentParserHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.Consumer; public class LiteFlowNodeBuilder { @@ -53,6 +49,10 @@ public class LiteFlowNodeBuilder { return new LiteFlowNodeBuilder(NodeTypeEnum.BREAK); } + public static LiteFlowNodeBuilder createIteratorNode() { + return new LiteFlowNodeBuilder(NodeTypeEnum.ITERATOR); + } + public static LiteFlowNodeBuilder createScriptNode() { return new LiteFlowNodeBuilder(NodeTypeEnum.SCRIPT); } @@ -130,8 +130,15 @@ public class LiteFlowNodeBuilder { if (StrUtil.isBlank(filePath)) { return this; } - String script = ResourceUtil.readUtf8Str(StrUtil.format("classpath: {}", filePath.trim())); - return setScript(script); + try { + List scriptList = PathContentParserHolder.loadContextAware().parseContent(ListUtil.toList(filePath)); + String script = CollUtil.getFirst(scriptList); + setScript(script); + } catch (Exception e) { + String errMsg = StrUtil.format("An exception occurred while building the node[{}],{}", this.node.getId(), e.getMessage()); + throw new NodeBuildException(errMsg); + } + return this; } public void build() { diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java index 0b0f720a0..6ad8f2ff4 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java @@ -1,18 +1,22 @@ package com.yomahub.liteflow.builder.el; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.StrUtil; import com.ql.util.express.DefaultContext; import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; import com.ql.util.express.exception.QLException; import com.yomahub.liteflow.builder.el.operator.*; import com.yomahub.liteflow.common.ChainConstant; -import com.yomahub.liteflow.exception.DataNofFoundException; +import com.yomahub.liteflow.exception.DataNotFoundException; import com.yomahub.liteflow.exception.ELParseException; 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.condition.*; +import com.yomahub.liteflow.flow.element.Node; +import com.yomahub.liteflow.flow.element.condition.Condition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,6 +73,7 @@ public class LiteFlowChainELBuilder { EXPRESS_RUNNER.addFunction(ChainConstant.NODE, new NodeOperator()); EXPRESS_RUNNER.addFunction(ChainConstant.FOR, new ForOperator()); EXPRESS_RUNNER.addFunction(ChainConstant.WHILE, new WhileOperator()); + EXPRESS_RUNNER.addFunction(ChainConstant.ITERATOR, new IteratorOperator()); EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DO, Object.class, new DoOperator()); EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BREAK, Object.class, new BreakOperator()); EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DATA, Object.class, new DataOperator()); @@ -151,8 +156,10 @@ public class LiteFlowChainELBuilder { return this; } catch (QLException e) { // EL 底层会包装异常,这里是曲线处理 - if (Objects.equals(e.getCause().getMessage(), DataNofFoundException.MSG)) { - throw new ELParseException(String.format("[node/chain is not exist or node/chain not register]elStr=%s", elStr)); + if (Objects.equals(e.getCause().getMessage(), DataNotFoundException.MSG)) { + // 构建错误信息 + String msg = buildDataNotFoundExceptionMsg(elStr); + throw new ELParseException(msg); } throw new ELParseException(e.getCause().getMessage()); } catch (Exception e) { @@ -162,17 +169,18 @@ public class LiteFlowChainELBuilder { /** * EL表达式校验 + * * @param elStr EL表达式 * @return true 校验成功 false 校验失败 */ public static boolean validate(String elStr) { - try { - LiteFlowChainELBuilder.createChain().setEL(elStr); - return Boolean.TRUE; - } catch (ELParseException e) { - LOG.error(e.getMessage()); - } - return Boolean.FALSE; + try { + LiteFlowChainELBuilder.createChain().setEL(elStr); + return Boolean.TRUE; + } catch (ELParseException e) { + LOG.error(e.getMessage()); + } + return Boolean.FALSE; } public void build() { @@ -183,6 +191,8 @@ public class LiteFlowChainELBuilder { FlowBus.addChain(this.chain); } + //#region private method + /** * build 前简单校验 */ @@ -195,4 +205,57 @@ public class LiteFlowChainELBuilder { throw new RuntimeException(CollUtil.join(errorList, ",", "[", "]")); } } + + /** + * 解析 EL 表达式,查找未定义的 id 并构建错误信息 + * + * @param elStr el 表达式 + */ + private String buildDataNotFoundExceptionMsg(String elStr) { + String msg = String.format("[node/chain is not exist or node/chain not register]\n EL: %s", StrUtil.trim(elStr)); + try { + InstructionSet parseResult = EXPRESS_RUNNER.getInstructionSetFromLocalCache(elStr); + if (parseResult == null) { + return msg; + } + + String[] outAttrNames = parseResult.getOutAttrNames(); + if (ArrayUtil.isEmpty(outAttrNames)) { + return msg; + } + + List chainIds = CollUtil.map(FlowBus.getChainMap().values(), Chain::getChainId, true); + List nodeIds = CollUtil.map(FlowBus.getNodeMap().values(), Node::getId, true); + for (String attrName : outAttrNames) { + if (!chainIds.contains(attrName) && !nodeIds.contains(attrName)) { + msg = String.format("[%s] is not exist or [%s] is not registered, you need to define a node or chain with id [%s] and register it \n EL: ", attrName, attrName, attrName); + + // 去除 EL 表达式中的空格和换行符 + String sourceEl = StrUtil.removeAll(elStr, CharUtil.SPACE, CharUtil.LF, CharUtil.CR); + // 这里需要注意的是,nodeId 和 chainId 可能是关键字的一部分,如果直接 indexOf(attrName) 会出现误判 + // 所以需要判断 attrName 前后是否有 "," + int commaRightIndex = sourceEl.indexOf(attrName + StrUtil.COMMA); + if (commaRightIndex != -1) { + // 需要加上 "EL: " 的长度 4,再加上 "^" 的长度 1,indexOf 从 0 开始,所以还需要加 1 + return msg + sourceEl + "\n" + StrUtil.fill("^", CharUtil.SPACE, commaRightIndex + 6, true); + } + int commaLeftIndex = sourceEl.indexOf(StrUtil.COMMA + attrName); + if (commaLeftIndex != -1) { + // 需要加上 "EL: " 的长度 4,再加上 "^" 的长度 1,再加上 "," 的长度 1,indexOf 从 0 开始,所以还需要加 1 + return msg + sourceEl + "\n" + StrUtil.fill("^", CharUtil.SPACE, commaLeftIndex + 7, true); + } + // 还有一种特殊情况,就是 EL 表达式中的节点使用 node("a") + int nodeIndex = sourceEl.indexOf(String.format("node(\"%s\")", attrName)); + if (nodeIndex != -1) { + // 需要加上 "EL: " 的长度 4,再加上 “node("” 长度 6,再加上 "^" 的长度 1,indexOf 从 0 开始,所以还需要加 1 + return msg + sourceEl + "\n" + StrUtil.fill("^", CharUtil.SPACE, commaLeftIndex + 12, true); + } + } + } + } catch (Exception ex) { + // ignore + } + return msg; + } + //#endregion } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IgnoreErrorOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IgnoreErrorOperator.java index e6990f6ce..ede076eb7 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IgnoreErrorOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IgnoreErrorOperator.java @@ -20,7 +20,7 @@ public class IgnoreErrorOperator extends BaseOperator { WhenCondition condition = OperatorHelper.convert(objects[0], WhenCondition.class); Boolean ignoreError = OperatorHelper.convert(objects[1], Boolean.class); - condition.setErrorResume(ignoreError); + condition.setIgnoreError(ignoreError); return condition; } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IteratorOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IteratorOperator.java new file mode 100644 index 000000000..9a19bdb78 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IteratorOperator.java @@ -0,0 +1,26 @@ +package com.yomahub.liteflow.builder.el.operator; + +import cn.hutool.core.collection.ListUtil; +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.Node; +import com.yomahub.liteflow.flow.element.condition.IteratorCondition; + +public class IteratorOperator extends BaseOperator { + @Override + public IteratorCondition build(Object[] objects) throws Exception { + OperatorHelper.checkObjectSizeEq(objects, 1); + + Node node = OperatorHelper.convert(objects[0], Node.class); + if (!ListUtil.toList(NodeTypeEnum.ITERATOR).contains(node.getType())) { + throw new QLException("The parameter must be iterator-node item"); + } + + IteratorCondition iteratorCondition = new IteratorCondition(); + iteratorCondition.setIteratorNode(node); + + return iteratorCondition; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/OperatorHelper.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/OperatorHelper.java index 401254036..88f60764b 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/OperatorHelper.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/OperatorHelper.java @@ -2,7 +2,7 @@ package com.yomahub.liteflow.builder.el.operator.base; import cn.hutool.core.util.StrUtil; import com.ql.util.express.exception.QLException; -import com.yomahub.liteflow.exception.DataNofFoundException; +import com.yomahub.liteflow.exception.DataNotFoundException; import com.yomahub.liteflow.flow.element.Node; import java.util.Objects; @@ -156,7 +156,7 @@ public class OperatorHelper { public static void checkNodeAndChainExist(Object[] objects) throws QLException { for (Object object : objects) { if (Objects.isNull(object)) { - throw new QLException(DataNofFoundException.MSG); + throw new QLException(DataNotFoundException.MSG); } } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java b/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java index baced9a62..a27f871c0 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java @@ -63,6 +63,8 @@ public interface ChainConstant { String DATA = "data"; + String ITERATOR = "ITERATOR"; + String MONITOR_BUS = "monitorBus"; String CURR_CHAIN_ID = "currChainId"; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java index 2fb35157a..da831e266 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java @@ -9,6 +9,7 @@ package com.yomahub.liteflow.core; import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.*; import com.yomahub.liteflow.enums.InnerChainTypeEnum; import com.yomahub.liteflow.exception.*; @@ -82,14 +83,16 @@ public class FlowExecutor { //进行id生成器的初始化 IdGeneratorHolder.init(); - if (StrUtil.isBlank(liteflowConfig.getRuleSource())) { + String ruleSource = liteflowConfig.getRuleSource(); + if (StrUtil.isBlank(ruleSource)) { //查看有没有Parser的SPI实现 //所有的Parser的SPI实现都是以custom形式放入的,且只支持xml形式 ServiceLoader loader = ServiceLoader.load(ParserClassNameSpi.class); Iterator it = loader.iterator(); if (it.hasNext()){ ParserClassNameSpi parserClassNameSpi = it.next(); - liteflowConfig.setRuleSource("el_xml:" + parserClassNameSpi.getSpiClassName()); + ruleSource = "el_xml:" + parserClassNameSpi.getSpiClassName(); + liteflowConfig.setRuleSource(ruleSource); }else{ //ruleSource为空,而且没有spi形式的扩展,那么说明真的没有ruleSource //这种情况有可能是基于代码动态构建的 @@ -100,10 +103,11 @@ public class FlowExecutor { //如果有前缀的,则不需要再进行分割了,说明是一个整体 //如果没有前缀,说明是本地文件,可能配置多个,所以需要分割 List sourceRulePathList; - if (ReUtil.contains(PREFIX_FORMAT_CONFIG_REGEX, liteflowConfig.getRuleSource())){ - sourceRulePathList = ListUtil.toList(liteflowConfig.getRuleSource()); - }else{ - sourceRulePathList = ListUtil.toList(liteflowConfig.getRuleSource().split(",|;")); + if (ReUtil.contains(PREFIX_FORMAT_CONFIG_REGEX, ruleSource)) { + sourceRulePathList = ListUtil.toList(ruleSource); + } else { + String afterHandleRuleSource = ruleSource.replace(StrUtil.SPACE, StrUtil.EMPTY); + sourceRulePathList = ListUtil.toList(afterHandleRuleSource.split(",|;")); } FlowParser parser = null; @@ -163,9 +167,11 @@ public class FlowExecutor { } //如果是ruleSource方式的,最后判断下有没有解析出来,如果没有解析出来则报错 - if (FlowBus.getChainMap().isEmpty()){ - String errMsg = StrUtil.format("no valid rule config found in rule path [{}]", liteflowConfig.getRuleSource()); - throw new ConfigErrorException(errMsg); + if (StrUtil.isBlank(liteflowConfig.getRuleSourceExtData()) && MapUtil.isEmpty(liteflowConfig.getRuleSourceExtDataMap())){ + if (FlowBus.getChainMap().isEmpty()){ + String errMsg = StrUtil.format("no valid rule config found in rule path [{}]", liteflowConfig.getRuleSource()); + throw new ConfigErrorException(errMsg); + } } //执行钩子 diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java index 5a397769c..fc44f66bd 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java @@ -92,7 +92,7 @@ public abstract class NodeComponent{ try{ //前置处理 - self.beforeProcess(this.getNodeId(), slot); + self.beforeProcess(); //主要的处理逻辑 self.process(); @@ -118,7 +118,7 @@ public abstract class NodeComponent{ throw e; } finally { //后置处理 - self.afterProcess(this.getNodeId(), slot); + self.afterProcess(); stopWatch.stop(); final long timeSpent = stopWatch.getTotalTimeMillis(); @@ -135,10 +135,10 @@ public abstract class NodeComponent{ } } - public void beforeProcess(String nodeId, Slot slot){ + public void beforeProcess(){ //全局切面只在spring体系下生效,这里用了spi机制取到相应环境下的实现类 //非spring环境下,全局切面为空实现 - CmpAroundAspectHolder.loadCmpAroundAspect().beforeProcess(nodeId, slot); + CmpAroundAspectHolder.loadCmpAroundAspect().beforeProcess(nodeId, this.getSlot()); } public abstract void process() throws Exception; @@ -151,8 +151,8 @@ public abstract class NodeComponent{ //如果需要在抛错后回调某一段逻辑,请覆盖这个方法 } - public void afterProcess(String nodeId, Slot slot){ - CmpAroundAspectHolder.loadCmpAroundAspect().afterProcess(nodeId, slot); + public void afterProcess(){ + CmpAroundAspectHolder.loadCmpAroundAspect().afterProcess(nodeId, this.getSlot()); } //是否进入该节点 @@ -349,6 +349,10 @@ public abstract class NodeComponent{ return this.refNodeTL.get().getLoopIndex(); } + public T getCurrLoopObj(){ + return this.refNodeTL.get().getCurrLoopObject(); + } + @Deprecated public void invoke(String chainId, Object param) throws Exception { FlowExecutorHolder.loadInstance().invoke(chainId, param, this.getSlotIndex()); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeIteratorComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeIteratorComponent.java new file mode 100644 index 000000000..03710dfcc --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeIteratorComponent.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.core; + +import com.yomahub.liteflow.slot.Slot; +import com.yomahub.liteflow.util.LiteFlowProxyUtil; + +import java.util.Iterator; + +/** + * ITERATOR迭代器循环组件抽象类 + * @author Bryan.Zhang + * @since 2.9.7 + */ +public abstract class NodeIteratorComponent extends NodeComponent{ + + @Override + public void process() throws Exception { + Iterator it = processIterator(); + Slot slot = this.getSlot(); + Class originalClass = LiteFlowProxyUtil.getUserClass(this.getClass()); + slot.setIteratorResult(originalClass.getName(), it); + } + + public abstract Iterator processIterator() throws Exception; +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ComponentProxy.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ComponentProxy.java index 4af0b8dd8..eb54fb175 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ComponentProxy.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ComponentProxy.java @@ -194,26 +194,17 @@ public class ComponentProxy { ).findFirst().orElse(null); //如果被代理的对象里有此标注标的方法,则调用此被代理的对象里的方法,如果没有,则调用父类里的方法 - //beforeProcess和afterProcess这2个方法除外 - if (!ListUtil.toList("beforeProcess","afterProcess").contains(liteFlowMethodBean.getMethodName())) { - //进行检查,检查被代理的bean里是否有且仅有NodeComponent这个类型的参数 - boolean checkFlag = liteFlowMethodBean.getMethod().getParameterTypes().length == 1 - && Arrays.asList(liteFlowMethodBean.getMethod().getParameterTypes()).contains(NodeComponent.class); - if (!checkFlag) { - String errMsg = StrUtil.format("Method[{}.{}] must have NodeComponent parameter(and only one parameter)", bean.getClass().getName(), liteFlowMethodBean.getMethod().getName()); - LOG.error(errMsg); - throw new ComponentMethodDefineErrorException(errMsg); - } - - try{ - return liteFlowMethodBean.getMethod().invoke(bean, proxy); - }catch (Exception e){ - InvocationTargetException targetEx = (InvocationTargetException)e; - throw targetEx.getTargetException(); - } + //进行检查,检查被代理的bean里是否有且仅有NodeComponent这个类型的参数 + boolean checkFlag = liteFlowMethodBean.getMethod().getParameterTypes().length == 1 + && Arrays.asList(liteFlowMethodBean.getMethod().getParameterTypes()).contains(NodeComponent.class); + if (!checkFlag) { + String errMsg = StrUtil.format("Method[{}.{}] must have NodeComponent parameter(and only one parameter)", bean.getClass().getName(), liteFlowMethodBean.getMethod().getName()); + LOG.error(errMsg); + throw new ComponentMethodDefineErrorException(errMsg); } + try{ - return liteFlowMethodBean.getMethod().invoke(bean, args); + return liteFlowMethodBean.getMethod().invoke(bean, proxy); }catch (Exception e){ InvocationTargetException targetEx = (InvocationTargetException)e; throw targetEx.getTargetException(); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ConditionTypeEnum.java b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ConditionTypeEnum.java index fa9178f26..f6c3faf2f 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ConditionTypeEnum.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ConditionTypeEnum.java @@ -14,7 +14,9 @@ public enum ConditionTypeEnum { TYPE_FOR("for", "for"), - TYPE_WHILE("while", "while") + TYPE_WHILE("while", "while"), + + TYPE_ITERATOR("iterator", "iterator") ; private String type; private String name; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/LiteFlowMethodEnum.java b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/LiteFlowMethodEnum.java index 739d37deb..91ee39bae 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/LiteFlowMethodEnum.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/LiteFlowMethodEnum.java @@ -7,6 +7,9 @@ public enum LiteFlowMethodEnum { PROCESS_FOR("processFor", true), PROCESS_WHILE("processWhile", true), PROCESS_BREAK("processBreak", true), + + PROCESS_ITERATOR("processIterator", true), + IS_ACCESS("isAccess", false), IS_END("isEnd", false), diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/NodeTypeEnum.java b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/NodeTypeEnum.java index afca14b6f..2c0806be2 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/NodeTypeEnum.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/NodeTypeEnum.java @@ -35,6 +35,8 @@ public enum NodeTypeEnum { BREAK("break", "循环跳出", false, NodeBreakComponent.class), + ITERATOR("iterator", "循环迭代", false, NodeIteratorComponent.class), + SCRIPT("script", "脚本", true, ScriptCommonComponent.class), SWITCH_SCRIPT("switch_script", "选择脚本", true, ScriptSwitchComponent.class), diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNofFoundException.java b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNotFoundException.java similarity index 67% rename from liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNofFoundException.java rename to liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNotFoundException.java index c31111517..cb2f65ad6 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNofFoundException.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNotFoundException.java @@ -4,8 +4,8 @@ package com.yomahub.liteflow.exception; * 未找到数据异常 * @author tangkc */ -public class DataNofFoundException extends RuntimeException { - public static final String MSG = "DataNofFoundException"; +public class DataNotFoundException extends RuntimeException { + public static final String MSG = "DataNotFoundException"; private static final long serialVersionUID = 1L; @@ -14,11 +14,11 @@ public class DataNofFoundException extends RuntimeException { */ private String message; - public DataNofFoundException() { + public DataNotFoundException() { this.message = MSG; } - public DataNofFoundException(String message) { + public DataNotFoundException(String message) { this.message = message; } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoIteratorNodeException.java b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoIteratorNodeException.java new file mode 100644 index 000000000..2e771aec4 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoIteratorNodeException.java @@ -0,0 +1,29 @@ +package com.yomahub.liteflow.exception; + +/** + * 没有节点异常 + * @author Yun + */ +public class NoIteratorNodeException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * 异常信息 + */ + private String message; + + public NoIteratorNodeException(String message) { + this.message = message; + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java index e7c42879d..95e2b1aa1 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java @@ -207,7 +207,7 @@ public class FlowBus { } catch (Exception e) { String error = StrUtil.format("component[{}] register error", StrUtil.isEmpty(name) ? nodeId : StrUtil.format("{}({})", nodeId, name)); LOG.error(e.getMessage()); - throw new ComponentCannotRegisterException(error); + throw new ComponentCannotRegisterException(StrUtil.format("{} {}", error, e.getMessage())); } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java index 64ed465cf..fc0cf0d01 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java @@ -56,6 +56,8 @@ public class Node implements Executable,Cloneable{ private TransmittableThreadLocal loopIndexTL = new TransmittableThreadLocal<>(); + private TransmittableThreadLocal currLoopObject = new TransmittableThreadLocal<>(); + public Node(){ } @@ -241,4 +243,16 @@ public class Node implements Executable,Cloneable{ public void removeLoopIndex(){ this.loopIndexTL.remove(); } + + public void setCurrLoopObject(Object obj){ + this.currLoopObject.set(obj); + } + + public T getCurrLoopObject(){ + return (T)this.currLoopObject.get(); + } + + public void removeCurrLoopObject(){ + this.currLoopObject.remove(); + } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java index 64d8c59c8..f6503478d 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java @@ -49,6 +49,7 @@ public class ForCondition extends LoopCondition{ //如果break组件不为空,则去执行 if (ObjectUtil.isNotNull(breakNode)){ breakNode.setCurrChainId(this.getCurrChainId()); + setLoopIndex(breakNode, i); breakNode.execute(slotIndex); Class originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getInstance().getClass()); boolean isBreak = slot.getBreakResult(originalBreakClass.getName()); @@ -64,10 +65,6 @@ public class ForCondition extends LoopCondition{ return ConditionTypeEnum.TYPE_FOR; } - public Executable getDoExecutor() { - return this.getExecutableList().get(0); - } - public Node getForNode() { return forNode; } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java new file mode 100644 index 000000000..e40141496 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java @@ -0,0 +1,78 @@ +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.NoIteratorNodeException; +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.Iterator; + +public class IteratorCondition extends LoopCondition{ + + private Node iteratorNode; + + @Override + public void execute(Integer slotIndex) throws Exception { + Slot slot = DataBus.getSlot(slotIndex); + if (ObjectUtil.isNull(iteratorNode)){ + String errorInfo = StrUtil.format("[{}]:no iterator-node found", slot.getRequestId()); + throw new NoIteratorNodeException(errorInfo); + } + + //执行Iterator组件 + iteratorNode.setCurrChainId(this.getCurrChainId()); + iteratorNode.execute(slotIndex); + + //这里可能会有spring代理过的bean,所以拿到user原始的class + Class originalForCountClass = LiteFlowProxyUtil.getUserClass(this.iteratorNode.getInstance().getClass()); + //获得迭代器 + Iterator it = slot.getIteratorResult(originalForCountClass.getName()); + + //获得要循环的可执行对象 + Executable executableItem = this.getDoExecutor(); + + int index = 0; + while(it.hasNext()){ + Object itObj = it.next(); + + executableItem.setCurrChainId(this.getCurrChainId()); + //设置循环index + setLoopIndex(executableItem, index); + //设置循环迭代器对象 + setCurrLoopObject(executableItem, itObj); + //执行可执行对象 + 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(this.breakNode.getInstance().getClass()); + boolean isBreak = slot.getBreakResult(originalBreakClass.getName()); + if (isBreak){ + break; + } + } + index++; + } + } + + @Override + public ConditionTypeEnum getConditionType() { + return ConditionTypeEnum.TYPE_ITERATOR; + } + + public Node getIteratorNode() { + return iteratorNode; + } + + public void setIteratorNode(Node iteratorNode) { + this.iteratorNode = iteratorNode; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java index c559585cd..6e2cc3cc3 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java @@ -32,4 +32,18 @@ public abstract class LoopCondition extends Condition { ((Node)executableItem).setLoopIndex(index); } } + + protected void setCurrLoopObject(Executable executableItem, Object obj){ + if (executableItem instanceof Chain){ + ((Chain)executableItem).getConditionList().forEach(condition -> setCurrLoopObject(condition, obj)); + }else if(executableItem instanceof Condition){ + ((Condition)executableItem).getExecutableList().forEach(executable -> setCurrLoopObject(executable, obj)); + }else if(executableItem instanceof Node){ + ((Node)executableItem).setCurrLoopObject(obj); + } + } + + protected Executable getDoExecutor() { + return this.getExecutableList().get(0); + } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/SwitchCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/SwitchCondition.java index 9f7a7c83d..9e26261df 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/SwitchCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/SwitchCondition.java @@ -45,9 +45,9 @@ public class SwitchCondition extends Condition{ //这里可能会有spring代理过的bean,所以拿到user原始的class Class originalClass = LiteFlowProxyUtil.getUserClass(this.getSwitchNode().getInstance().getClass()); String targetId = slot.getSwitchResult(originalClass.getName()); - if (StrUtil.isNotBlank(targetId)) { - Executable targetExecutor; + Executable targetExecutor = null; + if (StrUtil.isNotBlank(targetId)) { //这里要判断是否使用tag模式跳转 if (targetId.contains(TAG_FLAG)){ String[] target = targetId.split(TAG_FLAG, 2); @@ -66,26 +66,26 @@ public class SwitchCondition extends Condition{ executable -> executable.getExecuteId().equals(targetId) ).findFirst().orElse(null); } + } - if (ObjectUtil.isNull(targetExecutor)) { - //没有匹配到执行节点,则走默认的执行节点 - targetExecutor = defaultExecutor; - } + if (ObjectUtil.isNull(targetExecutor)) { + //没有匹配到执行节点,则走默认的执行节点 + targetExecutor = defaultExecutor; + } - if (ObjectUtil.isNotNull(targetExecutor)) { - //switch的目标不能是Pre节点或者Finally节点 - if (targetExecutor instanceof PreCondition || targetExecutor instanceof FinallyCondition){ - String errorInfo = StrUtil.format("[{}]:switch component[{}] error, switch target node cannot be pre or finally", - slot.getRequestId(), this.getSwitchNode().getInstance().getDisplayName()); - throw new SwitchTargetCannotBePreOrFinallyException(errorInfo); - } - targetExecutor.setCurrChainId(this.getCurrChainId()); - targetExecutor.execute(slotIndex); - }else{ - String errorInfo = StrUtil.format("[{}]:no target node find for the component[{}],target str is [{}]", - slot.getRequestId(), this.getSwitchNode().getInstance().getDisplayName(), targetId); - throw new NoSwitchTargetNodeException(errorInfo); + if (ObjectUtil.isNotNull(targetExecutor)) { + //switch的目标不能是Pre节点或者Finally节点 + if (targetExecutor instanceof PreCondition || targetExecutor instanceof FinallyCondition){ + String errorInfo = StrUtil.format("[{}]:switch component[{}] error, switch target node cannot be pre or finally", + slot.getRequestId(), this.getSwitchNode().getInstance().getDisplayName()); + throw new SwitchTargetCannotBePreOrFinallyException(errorInfo); } + targetExecutor.setCurrChainId(this.getCurrChainId()); + targetExecutor.execute(slotIndex); + }else{ + String errorInfo = StrUtil.format("[{}]:no target node find for the component[{}],target str is [{}]", + slot.getRequestId(), this.getSwitchNode().getInstance().getDisplayName(), targetId); + throw new NoSwitchTargetNodeException(errorInfo); } }else{ throw new SwitchTypeErrorException("switch instance must be NodeSwitchComponent"); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java index 4fc1037ee..2bdcdc777 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java @@ -37,7 +37,7 @@ public class WhenCondition extends Condition { private final Logger LOG = LoggerFactory.getLogger(this.getClass()); //只在when类型下有效,以区分当when调用链调用失败时是否继续往下执行 默认false不继续执行 - private boolean errorResume = false; + private boolean ignoreError = false; //只在when类型下有效,用于不同node进行同组合并,相同的组会进行合并,不同的组不会进行合并 //此属性已弃用 @@ -150,8 +150,8 @@ public class WhenCondition extends Condition { timeOutWhenFutureObjList.forEach(whenFutureObj -> LOG.warn("requestId [{}] executing thread has reached max-wait-seconds, thread canceled.Execute-item: [{}]", slot.getRequestId(), whenFutureObj.getExecutorName())); - //当配置了errorResume = false,出现interrupted或者!f.get()的情况,将抛出WhenExecuteException - if (!this.isErrorResume()) { + //当配置了ignoreError = false,出现interrupted或者!f.get()的情况,将抛出WhenExecuteException + if (!this.isIgnoreError()) { if (interrupted[0]) { throw new WhenExecuteException(StrUtil.format("requestId [{}] when execute interrupted. errorResume [false].", slot.getRequestId())); } @@ -164,17 +164,17 @@ public class WhenCondition extends Condition { } } } else if (interrupted[0]) { - // 这里由于配置了errorResume,所以只打印warn日志 + // 这里由于配置了ignoreError,所以只打印warn日志 LOG.warn("requestId [{}] executing when condition timeout , but ignore with errorResume.", slot.getRequestId()); } } - public boolean isErrorResume() { - return errorResume; + public boolean isIgnoreError() { + return ignoreError; } - public void setErrorResume(boolean errorResume) { - this.errorResume = errorResume; + public void setIgnoreError(boolean ignoreError) { + this.ignoreError = ignoreError; } public String getGroup() { diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java index 813832902..3e6773b55 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java @@ -35,11 +35,12 @@ public class WhileCondition extends LoopCondition{ int index = 0; while(getWhileResult(slotIndex)){ executableItem.setCurrChainId(this.getCurrChainId()); - setLoopIndex(executableItem, index++); + 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(this.breakNode.getInstance().getClass()); boolean isBreak = slot.getBreakResult(originalBreakClass.getName()); @@ -47,22 +48,19 @@ public class WhileCondition extends LoopCondition{ break; } } + index++; } } private boolean getWhileResult(Integer slotIndex) throws Exception{ Slot slot = DataBus.getSlot(slotIndex); //执行while组件 - whileNode.setCurrChainName(this.getCurrChainName()); + whileNode.setCurrChainId(this.getCurrChainId()); whileNode.execute(slotIndex); Class originalWhileClass = LiteFlowProxyUtil.getUserClass(this.whileNode.getInstance().getClass()); return slot.getWhileResult(originalWhileClass.getName()); } - public Executable getDoExecutor() { - return this.getExecutableList().get(0); - } - @Override public ConditionTypeEnum getConditionType() { return ConditionTypeEnum.TYPE_WHILE; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/slot/Slot.java b/liteflow-core/src/main/java/com/yomahub/liteflow/slot/Slot.java index 0425e161f..065639b05 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/slot/Slot.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/slot/Slot.java @@ -10,6 +10,7 @@ package com.yomahub.liteflow.slot; import cn.hutool.core.collection.ConcurrentHashSet; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.exception.NoSuchContextBeanException; import com.yomahub.liteflow.exception.NullParamException; import com.yomahub.liteflow.flow.entity.CmpStep; @@ -52,6 +53,8 @@ public class Slot{ private static final String WHILE_PREFIX = "_while_"; + private static final String ITERATOR_PREFIX = "_iterator_"; + private static final String BREAK_PREFIX = "_break_"; private static final String NODE_INPUT_PREFIX = "_input_"; @@ -89,6 +92,16 @@ public class Slot{ return metaDataMap.containsKey(key); } + private void putThreadMetaDataMap(String key, T t){ + String threadKey = StrUtil.format("{}_{}", key, Thread.currentThread().getName()); + putMetaDataMap(threadKey, t); + } + + private T getThreadMetaData(String key){ + String threadKey = StrUtil.format("{}_{}", key, Thread.currentThread().getName()); + return (T)metaDataMap.get(threadKey); + } + private void putMetaDataMap(String key, T t) { if (ObjectUtil.isNull(t)) { //data slot is a ConcurrentHashMap, so null value will trigger NullPointerException @@ -197,43 +210,51 @@ public class Slot{ } public void setSwitchResult(String key, T t){ - putMetaDataMap(SWITCH_NODE_PREFIX + key, t); + putThreadMetaDataMap(SWITCH_NODE_PREFIX + key, t); } public T getSwitchResult(String key){ - return (T) metaDataMap.get(SWITCH_NODE_PREFIX + key); + return getThreadMetaData(SWITCH_NODE_PREFIX + key); } public void setIfResult(String key, boolean result){ - putMetaDataMap(IF_NODE_PREFIX + key, result); + putThreadMetaDataMap(IF_NODE_PREFIX + key, result); } public boolean getIfResult(String key){ - return (boolean) metaDataMap.get(IF_NODE_PREFIX + key); + return getThreadMetaData(IF_NODE_PREFIX + key); } public void setForResult(String key, int forCount){ - putMetaDataMap(FOR_PREFIX + key, forCount); + putThreadMetaDataMap(FOR_PREFIX + key, forCount); } public int getForResult(String key){ - return (int) metaDataMap.get(FOR_PREFIX + key); + return getThreadMetaData(FOR_PREFIX + key); } public void setWhileResult(String key, boolean whileFlag){ - putMetaDataMap(WHILE_PREFIX + key, whileFlag); + putThreadMetaDataMap(WHILE_PREFIX + key, whileFlag); } public boolean getWhileResult(String key){ - return (boolean) metaDataMap.get(WHILE_PREFIX + key); + return getThreadMetaData(WHILE_PREFIX + key); } public void setBreakResult(String key, boolean breakFlag){ - putMetaDataMap(BREAK_PREFIX + key, breakFlag); + putThreadMetaDataMap(BREAK_PREFIX + key, breakFlag); } public boolean getBreakResult(String key){ - return (boolean) metaDataMap.get(BREAK_PREFIX + key); + return getThreadMetaData(BREAK_PREFIX + key); + } + + public void setIteratorResult(String key, Iterator it){ + putThreadMetaDataMap(ITERATOR_PREFIX + key, it); + } + + public Iterator getIteratorResult(String key){ + return getThreadMetaData(ITERATOR_PREFIX + key); } /** diff --git a/liteflow-core/src/main/resources/dtd/liteflow.dtd b/liteflow-core/src/main/resources/dtd/liteflow.dtd index d3faa5400..ed76a7fa2 100644 --- a/liteflow-core/src/main/resources/dtd/liteflow.dtd +++ b/liteflow-core/src/main/resources/dtd/liteflow.dtd @@ -1,15 +1,19 @@ - + \ No newline at end of file + id CDATA #IMPLIED + name CDATA #IMPLIED + > \ No newline at end of file diff --git a/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/solon/NodeComponentOfMethod.java b/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/solon/NodeComponentOfMethod.java index fbc58edb3..c2665b9dc 100644 --- a/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/solon/NodeComponentOfMethod.java +++ b/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/solon/NodeComponentOfMethod.java @@ -53,7 +53,7 @@ public class NodeComponentOfMethod extends NodeComponent { @Override - public void beforeProcess(String nodeId, Slot slot) { + public void beforeProcess() { if(methodEnum != LiteFlowMethodEnum.BEFORE_PROCESS){ return; } @@ -68,7 +68,7 @@ public class NodeComponentOfMethod extends NodeComponent { } @Override - public void afterProcess(String nodeId, Slot slot) { + public void afterProcess() { if (methodEnum != LiteFlowMethodEnum.AFTER_PROCESS) { return; } diff --git a/liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringPathContentParser.java b/liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringPathContentParser.java index 791f2789e..822aa411b 100644 --- a/liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringPathContentParser.java +++ b/liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringPathContentParser.java @@ -1,6 +1,5 @@ package com.yomahub.liteflow.spi.spring; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.io.FileUtil; @@ -9,19 +8,15 @@ import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.exception.ConfigErrorException; -import com.yomahub.liteflow.property.LiteflowConfig; -import com.yomahub.liteflow.property.LiteflowConfigGetter; import com.yomahub.liteflow.spi.PathContentParser; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.util.ResourceUtils; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; public class SpringPathContentParser implements PathContentParser { @Override diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/customMethodName/cmp/CmpConfig.java b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/customMethodName/cmp/CmpConfig.java index fd6293ca6..54ca00a24 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/customMethodName/cmp/CmpConfig.java +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/customMethodName/cmp/CmpConfig.java @@ -20,12 +20,12 @@ public class CmpConfig { } @LiteflowMethod(value = LiteFlowMethodEnum.BEFORE_PROCESS,nodeId = "a") - public void beforeAcmp(String nodeId, Slot slot){ + public void beforeAcmp(NodeComponent bindCmp){ System.out.println("before A"); } @LiteflowMethod(value = LiteFlowMethodEnum.AFTER_PROCESS,nodeId = "a") - public void afterAcmp(String nodeId, Slot slot){ + public void afterAcmp(NodeComponent bindCmp){ System.out.println("after A"); } diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELDeclMultiSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELDeclMultiSpringbootTest.java new file mode 100644 index 000000000..e8563a67e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELDeclMultiSpringbootTest.java @@ -0,0 +1,57 @@ +package com.yomahub.liteflow.test.iterator; + +import cn.hutool.core.collection.ListUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +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; +import java.util.List; + +/** + * springboot环境最普通的例子测试 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SpringRunner.class) +@TestPropertySource(value = "classpath:/iterator/application.properties") +@SpringBootTest(classes = IteratorELDeclMultiSpringbootTest.class) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.iterator.cmp"}) +public class IteratorELDeclMultiSpringbootTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + //最简单的情况 + @Test + public void testIt1() throws Exception{ + List list = ListUtil.toList("1","2","3"); + LiteflowResponse response = flowExecutor.execute2Resp("chain1", list); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + String str = context.getData("test"); + Assert.assertEquals("123", str); + } + + //迭代器带break + @Test + public void testIt2() throws Exception{ + List list = ListUtil.toList("1","2","3"); + LiteflowResponse response = flowExecutor.execute2Resp("chain2", list); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + String str = context.getData("test"); + Assert.assertEquals("12", str); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/CmpConfig.java b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/CmpConfig.java new file mode 100644 index 000000000..c63119279 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/CmpConfig.java @@ -0,0 +1,42 @@ +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import com.yomahub.liteflow.enums.NodeTypeEnum; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.base.cmp.TestDomain; + +import javax.annotation.Resource; +import java.util.Iterator; +import java.util.List; + +@LiteflowComponent +public class CmpConfig { + + @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "a") + public void processA(NodeComponent bindCmp) { + String key = "test"; + DefaultContext context = bindCmp.getFirstContextBean(); + if (!context.hasData(key)){ + context.setData(key, bindCmp.getCurrLoopObj()); + }else{ + String str = context.getData(key); + str += bindCmp.getCurrLoopObj(); + context.setData(key, str); + } + } + + @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_BREAK, nodeId = "b", nodeType = NodeTypeEnum.BREAK) + public boolean processB(NodeComponent bindCmp) { + return bindCmp.getLoopIndex() == 1; + } + @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_ITERATOR, nodeId = "it", nodeType = NodeTypeEnum.ITERATOR) + public Iterator processIT(NodeComponent bindCmp) { + List list = bindCmp.getRequestData(); + return list.iterator(); + } +} + + diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/iterator/application.properties b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/iterator/application.properties new file mode 100644 index 000000000..eee2ed632 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/iterator/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=iterator/flow.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/iterator/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/iterator/flow.xml new file mode 100644 index 000000000..7c732861a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/iterator/flow.xml @@ -0,0 +1,11 @@ + + + + + ITERATOR(it).DO(a); + + + + ITERATOR(it).DO(a).BREAK(b); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/customMethodName/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/customMethodName/cmp/ACmp.java index 6944cecd8..acfbcbf06 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/customMethodName/cmp/ACmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/customMethodName/cmp/ACmp.java @@ -27,12 +27,12 @@ public class ACmp{ } @LiteflowMethod(LiteFlowMethodEnum.BEFORE_PROCESS) - public void beforeAcmp(String nodeId, Slot slot){ + public void beforeAcmp(NodeComponent bindCmp){ System.out.println("before A"); } @LiteflowMethod(LiteFlowMethodEnum.AFTER_PROCESS) - public void afterAcmp(String nodeId, Slot slot){ + public void afterAcmp(NodeComponent bindCmp){ System.out.println("after A"); } diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELDeclSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELDeclSpringbootTest.java new file mode 100644 index 000000000..fdc1d51e9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELDeclSpringbootTest.java @@ -0,0 +1,57 @@ +package com.yomahub.liteflow.test.iterator; + +import cn.hutool.core.collection.ListUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +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; +import java.util.List; + +/** + * springboot环境最普通的例子测试 + * @author Bryan.Zhang + * @since 2.6.4 + */ +@RunWith(SpringRunner.class) +@TestPropertySource(value = "classpath:/iterator/application.properties") +@SpringBootTest(classes = IteratorELDeclSpringbootTest.class) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.iterator.cmp"}) +public class IteratorELDeclSpringbootTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + //最简单的情况 + @Test + public void testIt1() throws Exception{ + List list = ListUtil.toList("1","2","3"); + LiteflowResponse response = flowExecutor.execute2Resp("chain1", list); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + String str = context.getData("test"); + Assert.assertEquals("123", str); + } + + //迭代器带break + @Test + public void testIt2() throws Exception{ + List list = ListUtil.toList("1","2","3"); + LiteflowResponse response = flowExecutor.execute2Resp("chain2", list); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + String str = context.getData("test"); + Assert.assertEquals("12", str); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java new file mode 100644 index 000000000..fc53c287c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java @@ -0,0 +1,34 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.annotation.LiteflowCmpDefine; +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import com.yomahub.liteflow.enums.NodeTypeEnum; +import com.yomahub.liteflow.slot.DefaultContext; +import org.springframework.stereotype.Component; + +@Component("a") +@LiteflowCmpDefine(NodeTypeEnum.COMMON) +public class ACmp{ + + @LiteflowMethod(LiteFlowMethodEnum.PROCESS) + public void process(NodeComponent bindCmp) { + String key = "test"; + DefaultContext context = bindCmp.getFirstContextBean(); + if (!context.hasData(key)){ + context.setData(key, bindCmp.getCurrLoopObj()); + }else{ + String str = context.getData(key); + str += bindCmp.getCurrLoopObj(); + context.setData(key, str); + } + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java new file mode 100644 index 000000000..642ba8b35 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java @@ -0,0 +1,20 @@ + +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.annotation.LiteflowCmpDefine; +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeBreakComponent; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import com.yomahub.liteflow.enums.NodeTypeEnum; +import org.springframework.stereotype.Component; + +@Component("b") +@LiteflowCmpDefine(NodeTypeEnum.BREAK) +public class BCmp{ + + @LiteflowMethod(LiteFlowMethodEnum.PROCESS_BREAK) + public boolean processBreak(NodeComponent bindCmp) throws Exception { + return bindCmp.getLoopIndex() == 1; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java new file mode 100644 index 000000000..43c60973a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java @@ -0,0 +1,22 @@ +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.annotation.LiteflowCmpDefine; +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.core.NodeIteratorComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import com.yomahub.liteflow.enums.NodeTypeEnum; +import org.springframework.stereotype.Component; + +import java.util.Iterator; +import java.util.List; + +@Component("it") +@LiteflowCmpDefine(NodeTypeEnum.ITERATOR) +public class ITCmp{ + @LiteflowMethod(LiteFlowMethodEnum.PROCESS_ITERATOR) + public Iterator processIterator(NodeComponent bindCmp) throws Exception { + List list = bindCmp.getRequestData(); + return list.iterator(); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/subflow/SubflowInDifferentConfigELDeclSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/subflow/SubflowInDifferentConfigELDeclSpringbootTest.java index 83523d4f8..2bc3bf53e 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/subflow/SubflowInDifferentConfigELDeclSpringbootTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/subflow/SubflowInDifferentConfigELDeclSpringbootTest.java @@ -47,7 +47,7 @@ public class SubflowInDifferentConfigELDeclSpringbootTest extends BaseTest { @Test(expected = MultipleParsersException.class) public void testExplicitSubFlow2() { LiteflowConfig config = context.getBean(LiteflowConfig.class); - config.setRuleSource("subflow/flow-main.xml,subflow/flow-sub1.xml,subflow/flow-sub2.yml"); + config.setRuleSource("subflow/flow-main.xml, subflow/flow-sub1.xml,subflow/flow-sub2.yml"); flowExecutor.reloadRule(); } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/iterator/application.properties b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/iterator/application.properties new file mode 100644 index 000000000..eee2ed632 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/iterator/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=iterator/flow.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/iterator/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/iterator/flow.xml new file mode 100644 index 000000000..7c732861a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/iterator/flow.xml @@ -0,0 +1,11 @@ + + + + + ITERATOR(it).DO(a); + + + + ITERATOR(it).DO(a).BREAK(b); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/IteratorTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/IteratorTest.java new file mode 100644 index 000000000..5f3e2c0f4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/IteratorTest.java @@ -0,0 +1,48 @@ +package com.yomahub.liteflow.test.iterator; + +import cn.hutool.core.collection.ListUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.core.FlowExecutorHolder; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.List; + +public class IteratorTest extends BaseTest{ + + private static FlowExecutor flowExecutor; + + @BeforeClass + public static void init(){ + LiteflowConfig config = new LiteflowConfig(); + config.setRuleSource("iterator/flow.xml"); + flowExecutor = FlowExecutorHolder.loadInstance(config); + } + + //最简单的情况 + @Test + public void testIt1() throws Exception{ + List list = ListUtil.toList("1","2","3"); + LiteflowResponse response = flowExecutor.execute2Resp("chain1", list); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + String str = context.getData("test"); + Assert.assertEquals("123", str); + } + + //迭代器带break + @Test + public void testIt2() throws Exception{ + List list = ListUtil.toList("1","2","3"); + LiteflowResponse response = flowExecutor.execute2Resp("chain2", list); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + String str = context.getData("test"); + Assert.assertEquals("12", str); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java new file mode 100644 index 000000000..8d366b370 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java @@ -0,0 +1,27 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; + +public class ACmp extends NodeComponent { + + @Override + public void process() { + String key = "test"; + DefaultContext context = this.getFirstContextBean(); + if (!context.hasData(key)){ + context.setData(key, this.getCurrLoopObj()); + }else{ + String str = context.getData(key); + str += this.getCurrLoopObj(); + context.setData(key, str); + } + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java new file mode 100644 index 000000000..8ccfda17a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java @@ -0,0 +1,12 @@ + +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.core.NodeBreakComponent; + +public class BCmp extends NodeBreakComponent { + + @Override + public boolean processBreak() throws Exception { + return this.getLoopIndex() == 1; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java new file mode 100644 index 000000000..d3c5a763b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java @@ -0,0 +1,14 @@ +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.core.NodeIteratorComponent; + +import java.util.Iterator; +import java.util.List; + +public class ITCmp extends NodeIteratorComponent { + @Override + public Iterator processIterator() throws Exception { + List list = this.getRequestData(); + return list.iterator(); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/iterator/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/iterator/flow.xml new file mode 100644 index 000000000..f32f9169f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/iterator/flow.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + ITERATOR(it).DO(a); + + + + ITERATOR(it).DO(a).BREAK(b); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/common/LiteFlowXmlScriptBuilderGroovyELTest.java b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/common/LiteFlowXmlScriptBuilderGroovyELTest.java index e2c6468c8..5f46ffda1 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/common/LiteFlowXmlScriptBuilderGroovyELTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/common/LiteFlowXmlScriptBuilderGroovyELTest.java @@ -1,5 +1,6 @@ package com.yomahub.liteflow.test.script.groovy.common; +import cn.hutool.core.io.resource.ClassPathResource; import com.yomahub.liteflow.builder.LiteFlowNodeBuilder; import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; import com.yomahub.liteflow.core.FlowExecutor; @@ -25,6 +26,44 @@ public class LiteFlowXmlScriptBuilderGroovyELTest extends BaseTest { @Resource private FlowExecutor flowExecutor; + /** + * 测试通过builder方式运行普通script节点,以file绝对路径的方式运行 + */ + @Test + public void testAbsoluteScriptFilePath(){ + String absolutePath = new ClassPathResource("classpath:builder/s2.groovy").getAbsolutePath(); + LiteFlowNodeBuilder.createNode().setId("d") + .setName("组件D") + .setType(NodeTypeEnum.COMMON) + .setClazz("com.yomahub.liteflow.test.script.groovy.common.cmp.DCmp") + .build(); + LiteFlowNodeBuilder.createNode().setId("s2") + .setName("条件脚本S2") + .setType(NodeTypeEnum.SWITCH_SCRIPT) + .setFile(absolutePath) + .build(); + LiteFlowNodeBuilder.createNode().setId("a") + .setName("组件A") + .setType(NodeTypeEnum.COMMON) + .setClazz("com.yomahub.liteflow.test.script.groovy.common.cmp.ACmp") + .build(); + LiteFlowNodeBuilder.createNode().setId("b") + .setName("组件B") + .setType(NodeTypeEnum.COMMON) + .setClazz("com.yomahub.liteflow.test.script.groovy.common.cmp.BCmp") + .build(); + + LiteFlowChainELBuilder.createChain().setChainName("chain2") + .setEL("THEN(d,SWITCH(s2).to(a,b))") + .build(); + + + LiteflowResponse response = flowExecutor.execute2Resp("chain2","arg1"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("d[组件D]==>s2[条件脚本S2]==>a[组件A]", response.getExecuteStepStr()); + } + //测试通过builder方式运行普通script节点,以脚本文本的方式运行 @Test public void testBuilderScript1() { diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/scriptbean/LiteFlowScriptScriptbeanGroovyELTest.java b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/scriptbean/LiteFlowScriptScriptbeanGroovyELTest.java index 6eee3a732..64c78b0b7 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/scriptbean/LiteFlowScriptScriptbeanGroovyELTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/scriptbean/LiteFlowScriptScriptbeanGroovyELTest.java @@ -3,6 +3,7 @@ package com.yomahub.liteflow.test.script.groovy.scriptbean; import com.yomahub.liteflow.core.FlowExecutor; import com.yomahub.liteflow.exception.ScriptBeanMethodInvokeException; import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.script.ScriptBeanManager; import com.yomahub.liteflow.slot.DefaultContext; import com.yomahub.liteflow.test.BaseTest; import org.junit.Assert; @@ -15,6 +16,8 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; @RunWith(SpringRunner.class) @TestPropertySource(value = "classpath:/scriptbean/application.properties") @@ -75,4 +78,15 @@ public class LiteFlowScriptScriptbeanGroovyELTest extends BaseTest { Assert.assertFalse(response.isSuccess()); Assert.assertEquals(ScriptBeanMethodInvokeException.class, response.getCause().getClass()); } + + //测试在ScriptBeanManager里放入上下文,实现自定义脚本引用名称 + @Test + public void testScriptBean7() throws Exception{ + Map map = new HashMap<>(); + ScriptBeanManager.addScriptBean("abcCx", map); + LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg", map); + Assert.assertTrue(response.isSuccess()); + Map context = response.getFirstContextBean(); + Assert.assertEquals("hello", context.get("demo")); + } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/scriptbean/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/scriptbean/flow.xml index 397cff2c4..ac6c14749 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/scriptbean/flow.xml +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/scriptbean/flow.xml @@ -43,6 +43,13 @@ defaultContext.setData("demo", str) ]]> + + + + @@ -68,4 +75,8 @@ THEN(a,b,c,s4); + + + THEN(a,b,c,s5); + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-python-springboot/src/test/resources/common/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-script-python-springboot/src/test/resources/common/flow.xml index 3990c03e7..311888fe4 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-script-python-springboot/src/test/resources/common/flow.xml +++ b/liteflow-testcase-el/liteflow-testcase-el-script-python-springboot/src/test/resources/common/flow.xml @@ -1,8 +1,16 @@ + - + 5: diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java new file mode 100644 index 000000000..dc26c7be0 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java @@ -0,0 +1,55 @@ +package com.yomahub.liteflow.test.iterator; + +import cn.hutool.core.collection.ListUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +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; +import java.util.List; + +/** + * springboot环境EL常规的例子测试 + * @author Bryan.Zhang + */ +@RunWith(SpringRunner.class) +@TestPropertySource(value = "classpath:/iterator/application.properties") +@SpringBootTest(classes = IteratorELSpringbootTest.class) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.iterator.cmp"}) +public class IteratorELSpringbootTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + //最简单的情况 + @Test + public void testIt1() throws Exception{ + List list = ListUtil.toList("1","2","3"); + LiteflowResponse response = flowExecutor.execute2Resp("chain1", list); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + String str = context.getData("test"); + Assert.assertEquals("123", str); + } + + //迭代器带break + @Test + public void testIt2() throws Exception{ + List list = ListUtil.toList("1","2","3"); + LiteflowResponse response = flowExecutor.execute2Resp("chain2", list); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + String str = context.getData("test"); + Assert.assertEquals("12", str); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java new file mode 100644 index 000000000..665236a0f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java @@ -0,0 +1,29 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.springframework.stereotype.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + String key = "test"; + DefaultContext context = this.getFirstContextBean(); + if (!context.hasData(key)){ + context.setData(key, this.getCurrLoopObj()); + }else{ + String str = context.getData(key); + str += this.getCurrLoopObj(); + context.setData(key, str); + } + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java new file mode 100644 index 000000000..74110c698 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java @@ -0,0 +1,15 @@ + +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.core.NodeBreakComponent; +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("b") +public class BCmp extends NodeBreakComponent { + + @Override + public boolean processBreak() throws Exception { + return this.getLoopIndex() == 1; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java new file mode 100644 index 000000000..cc36766d7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java @@ -0,0 +1,16 @@ +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.core.NodeIteratorComponent; +import org.springframework.stereotype.Component; + +import java.util.Iterator; +import java.util.List; + +@Component("it") +public class ITCmp extends NodeIteratorComponent { + @Override + public Iterator processIterator() throws Exception { + List list = this.getRequestData(); + return list.iterator(); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchELSpringbootTest.java index c94bb45ee..d043364b9 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchELSpringbootTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchELSpringbootTest.java @@ -84,4 +84,12 @@ public class SwitchELSpringbootTest extends BaseTest { Assert.assertEquals("a==>i==>d",response.getExecuteStepStr()); } + //switch返回如果是空,会走default选项 + @Test + public void testSwitch8() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain8", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("a==>j==>d",response.getExecuteStepStr()); + } + } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/JSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/JSwitchCmp.java new file mode 100644 index 000000000..0e70272e5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/JSwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Tingliang Wang + * @email bytlwang@126.com + * @Date 2022/12/09 + */ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.springframework.stereotype.Component; + +@Component("j") +public class JSwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return ""; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/iterator/application.properties b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/iterator/application.properties new file mode 100644 index 000000000..eee2ed632 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/iterator/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=iterator/flow.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/iterator/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/iterator/flow.xml new file mode 100644 index 000000000..7c732861a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/iterator/flow.xml @@ -0,0 +1,11 @@ + + + + + ITERATOR(it).DO(a); + + + + ITERATOR(it).DO(a).BREAK(b); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/switchcase/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/switchcase/flow.el.xml index ee853dd0b..227eaf43a 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/switchcase/flow.el.xml +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/switchcase/flow.el.xml @@ -50,4 +50,10 @@ );
+ + THEN( + a, + SWITCH(j).to(b, c).DEFAULT(d) + ); + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringTest.java b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringTest.java new file mode 100644 index 000000000..207a48986 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringTest.java @@ -0,0 +1,45 @@ +package com.yomahub.liteflow.test.iterator; + +import cn.hutool.core.collection.ListUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.util.List; + +@RunWith(SpringRunner.class) +@ContextConfiguration("classpath:/iterator/application.xml") +public class IteratorELSpringTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + //最简单的情况 + @Test + public void testIt1() throws Exception{ + List list = ListUtil.toList("1","2","3"); + LiteflowResponse response = flowExecutor.execute2Resp("chain1", list); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + String str = context.getData("test"); + Assert.assertEquals("123", str); + } + + //迭代器带break + @Test + public void testIt2() throws Exception{ + List list = ListUtil.toList("1","2","3"); + LiteflowResponse response = flowExecutor.execute2Resp("chain2", list); + Assert.assertTrue(response.isSuccess()); + DefaultContext context = response.getFirstContextBean(); + String str = context.getData("test"); + Assert.assertEquals("12", str); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java new file mode 100644 index 000000000..665236a0f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ACmp.java @@ -0,0 +1,29 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.springframework.stereotype.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + String key = "test"; + DefaultContext context = this.getFirstContextBean(); + if (!context.hasData(key)){ + context.setData(key, this.getCurrLoopObj()); + }else{ + String str = context.getData(key); + str += this.getCurrLoopObj(); + context.setData(key, str); + } + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java new file mode 100644 index 000000000..cc7d0e748 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/cmp/BCmp.java @@ -0,0 +1,14 @@ + +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.core.NodeBreakComponent; +import org.springframework.stereotype.Component; + +@Component("b") +public class BCmp extends NodeBreakComponent { + + @Override + public boolean processBreak() throws Exception { + return this.getLoopIndex() == 1; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java new file mode 100644 index 000000000..cc36766d7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/java/com/yomahub/liteflow/test/iterator/cmp/ITCmp.java @@ -0,0 +1,16 @@ +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.core.NodeIteratorComponent; +import org.springframework.stereotype.Component; + +import java.util.Iterator; +import java.util.List; + +@Component("it") +public class ITCmp extends NodeIteratorComponent { + @Override + public Iterator processIterator() throws Exception { + List list = this.getRequestData(); + return list.iterator(); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/resources/iterator/application.xml b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/resources/iterator/application.xml new file mode 100644 index 000000000..d5a2e14c2 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/resources/iterator/application.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/resources/iterator/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/resources/iterator/flow.xml new file mode 100644 index 000000000..7c732861a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springnative/src/test/resources/iterator/flow.xml @@ -0,0 +1,11 @@ + + + + + ITERATOR(it).DO(a); + + + + ITERATOR(it).DO(a).BREAK(b); + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8b7a09656..bce9dc06b 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ - 2.9.6 + 2.9.7 UTF-8 UTF-8 8 @@ -52,7 +52,7 @@ 2.1.3 5.3.0 4.12 - 5.8.8 + 5.8.11 2.12.3 5.1.0 0.10 @@ -64,9 +64,7 @@ 1.11.13 1.8.13 1.2.3 - - 1.12.0 - + 2.0.0 4.1.84.Final 31.1-jre 4.5.13