Przeglądaj źródła

feature #I44FT8 支持脚本语言的组件,并支持动态刷新脚本(版本特性)

bryan31 3 lat temu
rodzic
commit
2d6cb55d1d

+ 11 - 0
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;
+	}
 }

+ 6 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptNodeComponent.java → 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);
     }
 }

+ 20 - 0
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);
+    }
+}

+ 12 - 1
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<String, Executable> 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;
 	}

+ 45 - 0
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;
+    }
+}

+ 27 - 0
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;
+	}
+}

+ 27 - 13
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<NodeComponent> cmpClazz = (Class<NodeComponent>) 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<? extends NodeComponent> 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<? extends NodeComponent> 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<? extends NodeComponent> cmpClazz, String script) {
+    private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<? extends NodeComponent> 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);
-
-            //如果是脚本节点,则还要加载script脚本
-            if (cmpClazz.equals(ScriptNodeComponent.class) && StrUtil.isNotBlank(script)){
-                ((ScriptNodeComponent)cmpInstance).loadScript(script);
+            cmpInstance.setType(type);
+
+            //如果是脚本节点(普通脚本节点/条件脚本节点),则还要加载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());

+ 3 - 3
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<String, NodeComponent> 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);
                             }
                         }
                     }

+ 23 - 6
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<String, NodeComponent> 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 {
                 // 当存在<nodes>节点定义时,解析node节点
                 if (ObjectUtil.isNotNull(nodesElement)){
                     List<Element> 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);
+                                }
                             }
                         }
                     }

+ 1 - 1
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();
 }

+ 2 - 2
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<String> errorList = new ArrayList<>();
         try{
             Slot slot = DataBus.getSlot(slotIndex);
             DefaultContext<String, Object> context = new DefaultContext<String, Object>();
             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);

+ 1 - 1
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<DefaultSlot> response= flowExecutor.execute2Resp("chain1", "it's a request");
         Assert.assertTrue(response.isSuccess());
         Assert.assertEquals("a==>b==>c==>d", response.getSlot().printStep());

+ 1 - 1
liteflow-spring-boot-starter/src/test/resources/scriptnode/flow.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <flow>
     <nodes>
-        <node id="s1">
+        <node id="s1" type="script">
             <![CDATA[
                 a=3;
                 b=2;