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 c8f31280f..6ddd61810 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 @@ -11,6 +11,7 @@ import cn.hutool.core.date.StopWatch; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.ttl.TransmittableThreadLocal; +import com.yomahub.liteflow.enums.NodeTypeEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -43,6 +44,8 @@ public abstract class NodeComponent { private String name; + private NodeTypeEnum type; + //这是自己的实例,取代this //为何要设置这个,用this不行么,因为如果有aop去切的话,this在spring的aop里是切不到的。self对象有可能是代理过的对象 private NodeComponent self; @@ -172,4 +175,12 @@ public abstract class NodeComponent { public void setName(String name) { this.name = name; } + + public NodeTypeEnum getType() { + return type; + } + + public void setType(NodeTypeEnum type) { + this.type = type; + } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptNodeComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptComponent.java similarity index 65% rename from liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptNodeComponent.java rename to liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptComponent.java index f9696e9a5..2f277bf56 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptNodeComponent.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptComponent.java @@ -1,13 +1,17 @@ package com.yomahub.liteflow.core; import com.yomahub.liteflow.script.ScriptExecutorFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * 脚本组件类 * @author Bryan.Zhang * @since 2.5.11 */ -public class ScriptNodeComponent extends NodeComponent{ +public class ScriptComponent extends NodeComponent{ + + private final Logger log = LoggerFactory.getLogger(this.getClass()); @Override public void process() throws Exception { @@ -15,6 +19,7 @@ public class ScriptNodeComponent extends NodeComponent{ } public void loadScript(String script) { + log.info("load script for component[{}]", getNodeId()); ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script); } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptCondComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptCondComponent.java new file mode 100644 index 000000000..34a5dd48c --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptCondComponent.java @@ -0,0 +1,20 @@ +package com.yomahub.liteflow.core; + +import com.yomahub.liteflow.script.ScriptExecutorFactory; + +/** + * 脚本条件节点 + * @author Bryan.Zhang + * @since 2.5.11 + */ +public class ScriptCondComponent extends NodeCondComponent{ + + @Override + public String processCond() throws Exception { + return (String)ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(getNodeId(), getSlotIndex()); + } + + public void loadScript(String script) { + ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java index 285b98c39..811dd38c2 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java @@ -14,10 +14,10 @@ import java.util.Map; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.core.NodeComponent; -import com.yomahub.liteflow.core.ScriptNodeComponent; import com.yomahub.liteflow.entity.data.DataBus; import com.yomahub.liteflow.entity.data.Slot; import com.yomahub.liteflow.enums.ExecuteTypeEnum; +import com.yomahub.liteflow.enums.NodeTypeEnum; import com.yomahub.liteflow.exception.ChainEndException; import com.yomahub.liteflow.exception.FlowSystemException; import org.slf4j.Logger; @@ -35,6 +35,8 @@ public class Node implements Executable{ private String name; + private NodeTypeEnum type; + private NodeComponent instance; private final Map condNodeMap = new HashMap<>(); @@ -47,6 +49,7 @@ public class Node implements Executable{ this.id = instance.getNodeId(); this.name = instance.getName(); this.instance = instance; + this.type = instance.getType(); } public String getId() { @@ -65,6 +68,14 @@ public class Node implements Executable{ this.name = name; } + public NodeTypeEnum getType() { + return type; + } + + public void setType(NodeTypeEnum type) { + this.type = type; + } + public NodeComponent getInstance() { return instance; } 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 new file mode 100644 index 000000000..cf6d601b1 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/NodeTypeEnum.java @@ -0,0 +1,45 @@ +package com.yomahub.liteflow.enums; + +/** + * 节点类型枚举 + * @author Bryan.Zhang + * @since 2.5.11 + */ +public enum NodeTypeEnum { + COMMON("common","普通"), + SCRIPT("script","脚本"), + COND_SCRIPT("cond_script","条件脚本") + ; + private String code; + private String name; + + NodeTypeEnum(String code, String name) { + this.code = code; + this.name = name; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static NodeTypeEnum getEnumByCode(String code) { + for (NodeTypeEnum e : NodeTypeEnum.values()) { + if (e.getCode().equals(code)) { + return e; + } + } + return null; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NodeTypeNotSupportException.java b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NodeTypeNotSupportException.java new file mode 100644 index 000000000..fe4d12cf7 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NodeTypeNotSupportException.java @@ -0,0 +1,27 @@ + +package com.yomahub.liteflow.exception; + +/** + * 节点类型不支持异常 + * @author Bryan.Zhang + * @since 2.5.11 + */ +public class NodeTypeNotSupportException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** 异常信息 */ + private String message; + + public NodeTypeNotSupportException(String message) { + this.message = message; + } + + 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 6af50127d..062a41e73 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 @@ -12,11 +12,14 @@ import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.core.NodeComponent; -import com.yomahub.liteflow.core.ScriptNodeComponent; +import com.yomahub.liteflow.core.ScriptComponent; +import com.yomahub.liteflow.core.ScriptCondComponent; import com.yomahub.liteflow.entity.flow.Chain; import com.yomahub.liteflow.entity.flow.Node; import com.yomahub.liteflow.enums.FlowParserTypeEnum; +import com.yomahub.liteflow.enums.NodeTypeEnum; import com.yomahub.liteflow.exception.ComponentCannotRegisterException; +import com.yomahub.liteflow.exception.NodeTypeNotSupportException; import com.yomahub.liteflow.parser.LocalJsonFlowParser; import com.yomahub.liteflow.parser.LocalXmlFlowParser; import com.yomahub.liteflow.parser.LocalYmlFlowParser; @@ -68,27 +71,32 @@ public class FlowBus { return nodeMap.containsKey(nodeId); } - public static void addNode(String nodeId, Node node) { + public static void addCommonNode(String nodeId, Node node) { if (containNode(nodeId)) return; nodeMap.put(nodeId, node); } - public static void addNode(String nodeId, String name, String cmpClazzStr) throws Exception { + public static void addCommonNode(String nodeId, String name, String cmpClazzStr) throws Exception { if (containNode(nodeId)) return; Class cmpClazz = (Class) Class.forName(cmpClazzStr); - addNode(nodeId, name ,cmpClazz, null); + addNode(nodeId, name, NodeTypeEnum.COMMON, cmpClazz, null); } - public static void addScriptNode(String nodeId, String name, String script){ + public static void addCommonNode(String nodeId, Class cmpClazz){ + addNode(nodeId, null, NodeTypeEnum.COMMON, cmpClazz, null); + } + + public static void addCommonScriptNode(String nodeId, String name, String script){ if (containNode(nodeId)) return; - addNode(nodeId, name , ScriptNodeComponent.class, script); + addNode(nodeId, name, NodeTypeEnum.SCRIPT, ScriptComponent.class, script); } - public static void addNode(String nodeId, Class cmpClazz){ - addNode(nodeId, null, cmpClazz, null); + public static void addCondScriptNode(String nodeId, String name, String script){ + if (containNode(nodeId)) return; + addNode(nodeId, name, NodeTypeEnum.COND_SCRIPT, ScriptCondComponent.class, script); } - public static void addNode(String nodeId, String name, Class cmpClazz, String script) { + private static void addNode(String nodeId, String name, NodeTypeEnum type, Class cmpClazz, String script) { if (containNode(nodeId)) return; try { //以node方式配置,本质上是为了适配无spring的环境,如果有spring环境,其实不用这么配置 @@ -101,11 +109,17 @@ public class FlowBus { cmpInstance.setNodeId(nodeId); cmpInstance.setName(name); cmpInstance.setSelf(cmpInstance); + cmpInstance.setType(type); - //如果是脚本节点,则还要加载script脚本 - if (cmpClazz.equals(ScriptNodeComponent.class) && StrUtil.isNotBlank(script)){ - ((ScriptNodeComponent)cmpInstance).loadScript(script); + //如果是脚本节点(普通脚本节点/条件脚本节点),则还要加载script脚本 + if (StrUtil.isNotBlank(script)){ + if (type.equals(NodeTypeEnum.SCRIPT)){ + ((ScriptComponent)cmpInstance).loadScript(script); + }else if(type.equals(NodeTypeEnum.COND_SCRIPT)){ + ((ScriptCondComponent)cmpInstance).loadScript(script); + } } + nodeMap.put(nodeId, new Node(cmpInstance)); } catch (Exception e) { String error = StrUtil.format("component[{}] register error", cmpClazz.getName()); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/JsonFlowParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/JsonFlowParser.java index a51972c4a..b140798be 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/JsonFlowParser.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/JsonFlowParser.java @@ -52,7 +52,7 @@ public abstract class JsonFlowParser extends FlowParser { try { for (Map.Entry componentEntry : ComponentScanner.nodeComponentMap.entrySet()) { if (!FlowBus.containNode(componentEntry.getKey())) { - FlowBus.addNode(componentEntry.getKey(), new Node(componentEntry.getValue())); + FlowBus.addCommonNode(componentEntry.getKey(), new Node(componentEntry.getValue())); } } @@ -70,12 +70,12 @@ public abstract class JsonFlowParser extends FlowParser { //如果有class的定义,则表明是java组件,无class的定义,则表明是脚本组件 if (StrUtil.isNotBlank(clazz)){ if (!FlowBus.containNode(id)){ - FlowBus.addNode(id, name, clazz); + FlowBus.addCommonNode(id, name, clazz); } }else{ if (!FlowBus.containNode(id)){ script = nodeObject.getString("script"); - FlowBus.addScriptNode(id, name, script); + FlowBus.addCommonScriptNode(id, name, script); } } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java index 471d2b92a..6e4fa757f 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java @@ -10,7 +10,9 @@ import com.yomahub.liteflow.entity.flow.Chain; import com.yomahub.liteflow.entity.flow.Condition; import com.yomahub.liteflow.entity.flow.Executable; import com.yomahub.liteflow.entity.flow.Node; +import com.yomahub.liteflow.enums.NodeTypeEnum; import com.yomahub.liteflow.exception.ExecutableItemNotFoundException; +import com.yomahub.liteflow.exception.NodeTypeNotSupportException; import com.yomahub.liteflow.exception.ParseException; import com.yomahub.liteflow.flow.FlowBus; import com.yomahub.liteflow.spring.ComponentScanner; @@ -56,7 +58,7 @@ public abstract class XmlFlowParser extends FlowParser { //先进行Spring上下文中的节点的判断 for (Entry componentEntry : ComponentScanner.nodeComponentMap.entrySet()) { if (!FlowBus.containNode(componentEntry.getKey())) { - FlowBus.addNode(componentEntry.getKey(), new Node(componentEntry.getValue())); + FlowBus.addCommonNode(componentEntry.getKey(), new Node(componentEntry.getValue())); } } @@ -66,21 +68,36 @@ public abstract class XmlFlowParser extends FlowParser { // 当存在节点定义时,解析node节点 if (ObjectUtil.isNotNull(nodesElement)){ List nodeList = nodesElement.elements("node"); - String id, name, clazz, script; + String id, name, clazz, type, script; for (Element e : nodeList) { id = e.attributeValue("id"); name = e.attributeValue("name"); clazz = e.attributeValue("class"); + type = e.attributeValue("type"); - //如果有class的定义,则表明是java组件,无class的定义,则表明是脚本组件 - if (StrUtil.isNotBlank(clazz)){ + //初始化type + if (StrUtil.isBlank(type)){ + type = NodeTypeEnum.COMMON.getCode(); + } + NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type); + if (ObjectUtil.isNull(nodeTypeEnum)){ + throw new NodeTypeNotSupportException(StrUtil.format("type [{}] is not support", type)); + } + + //这里区分是普通java节点还是脚本节点 + //如果是脚本节点,又区分是普通脚本节点,还是条件脚本节点 + if (nodeTypeEnum.equals(NodeTypeEnum.COMMON) && StrUtil.isNotBlank(clazz)){ if (!FlowBus.containNode(id)){ - FlowBus.addNode(id, name, clazz); + FlowBus.addCommonNode(id, name, clazz); } }else{ if (!FlowBus.containNode(id)){ script = e.getTextTrim(); - FlowBus.addScriptNode(id, name, script); + if (nodeTypeEnum.equals(NodeTypeEnum.SCRIPT)){ + FlowBus.addCommonScriptNode(id, name, script); + }else if(nodeTypeEnum.equals(NodeTypeEnum.COND_SCRIPT)){ + FlowBus.addCondScriptNode(id, name, script); + } } } } diff --git a/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/ScriptExecutor.java b/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/ScriptExecutor.java index acacbceff..4a362f452 100644 --- a/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/ScriptExecutor.java +++ b/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/ScriptExecutor.java @@ -11,7 +11,7 @@ public interface ScriptExecutor { void load(String nodeId, String script); - void execute(String nodeId, int slotIndex); + Object execute(String nodeId, int slotIndex); void cleanCache(); } diff --git a/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java b/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java index d7c43a7fc..162686b1e 100644 --- a/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java +++ b/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java @@ -37,13 +37,13 @@ public class QLExpressScriptExecutor implements ScriptExecutor { } @Override - public void execute(String nodeId, int slotIndex) { + public Object execute(String nodeId, int slotIndex) { List errorList = new ArrayList<>(); try{ Slot slot = DataBus.getSlot(slotIndex); DefaultContext context = new DefaultContext(); context.put("slot", slot); - expressRunner.executeByExpressName(nodeId, context, errorList, true, false, null); + return expressRunner.executeByExpressName(nodeId, context, errorList, true, false, null); }catch (Exception e){ for (String scriptErrorMsg : errorList){ log.error("\n{}", scriptErrorMsg); diff --git a/liteflow-spring-boot-starter/src/test/java/com/yomahub/liteflow/test/flowmeta/FlowMetaSpringbootTest.java b/liteflow-spring-boot-starter/src/test/java/com/yomahub/liteflow/test/flowmeta/FlowMetaSpringbootTest.java index b6b98ffeb..e6430e222 100644 --- a/liteflow-spring-boot-starter/src/test/java/com/yomahub/liteflow/test/flowmeta/FlowMetaSpringbootTest.java +++ b/liteflow-spring-boot-starter/src/test/java/com/yomahub/liteflow/test/flowmeta/FlowMetaSpringbootTest.java @@ -30,7 +30,7 @@ public class FlowMetaSpringbootTest extends BaseTest { //测试动态添加元信息节点 @Test public void testFlowMeta() { - FlowBus.addNode("d", DCmp.class); + FlowBus.addCommonNode("d", DCmp.class); LiteflowResponse response= flowExecutor.execute2Resp("chain1", "it's a request"); Assert.assertTrue(response.isSuccess()); Assert.assertEquals("a==>b==>c==>d", response.getSlot().printStep()); diff --git a/liteflow-spring-boot-starter/src/test/resources/scriptnode/flow.xml b/liteflow-spring-boot-starter/src/test/resources/scriptnode/flow.xml index b26ffdf0e..a33b7c15d 100644 --- a/liteflow-spring-boot-starter/src/test/resources/scriptnode/flow.xml +++ b/liteflow-spring-boot-starter/src/test/resources/scriptnode/flow.xml @@ -1,7 +1,7 @@ - +