Browse Source

enhancement #IBJO4X 建立统一元数据操作类,所有元数据的操作的入口

everywhere.z 3 months ago
parent
commit
9853e3e460
14 changed files with 306 additions and 17 deletions
  1. 0 2
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java
  2. 6 0
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java
  3. 8 12
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/BaseNodeInstanceIdManageSpi.java
  4. 1 1
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/NodeInstanceIdManageSpi.java
  5. 158 0
      liteflow-core/src/main/java/com/yomahub/liteflow/meta/LiteflowMetaOperator.java
  6. 55 0
      liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/java/com/yomahub/liteflow/test/script/javaxpro/refresh/ScriptJavaxProRefreshELTest.java
  7. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/java/com/yomahub/liteflow/test/script/javaxpro/refresh/cmp/ACmp.java
  8. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/java/com/yomahub/liteflow/test/script/javaxpro/refresh/cmp/BCmp.java
  9. 2 0
      liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/resources/refresh/application.properties
  10. 8 0
      liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/resources/refresh/flow.xml
  11. 12 0
      liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/resources/refresh/s1.java
  12. 12 0
      liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/resources/refresh/s1_update.java
  13. 1 1
      liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/instanceIds/InstanceIdELSpringTest.java
  14. 1 1
      liteflow-testcase-el/liteflow-testcase-el-sql-springboot/src/test/java/com/yomahub/liteflow/test/sqlInstanceId/SQLWithXmlELInstanceIdSpringbootTest.java

+ 0 - 2
liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java

@@ -273,9 +273,7 @@ public class FlowBus {
 						throw new ScriptLoadException(errorMsg);
 					}
 				}
-
 				String activeNodeId = StrUtil.isEmpty(cmpInstance.getNodeId()) ? nodeId : cmpInstance.getNodeId();
-                node.setCompiled(true);
 				put2NodeMap(activeNodeId, node);
 				addFallbackNode(node);
 			}

+ 6 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java

@@ -185,6 +185,12 @@ public class Node implements Executable, Cloneable, Rollbackable{
 					.buildNodeExecutor(instance.getNodeExecutorClass());
 				// 调用节点执行器进行执行
 				nodeExecutor.execute(instance);
+
+				// 如果是脚本节点,并且是后置编译的,那么在成功执行好脚本节点后把编译flag置为true
+				// 这个只能在成功执行好之后设置,如果在编译好之后设置,那么设置的只有FlowBus中的nodeMap中的
+				if (this.type.isScript() && !this.isCompiled){
+					this.setCompiled(true);
+				}
 			} else {
 				LOG.info("[X]skip component[{}] execution", instance.getDisplayName());
 			}

+ 8 - 12
liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/BaseNodeInstanceIdManageSpi.java

@@ -5,14 +5,11 @@ import cn.hutool.crypto.digest.MD5;
 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.Executable;
 import com.yomahub.liteflow.flow.element.Node;
 import com.yomahub.liteflow.flow.entity.InstanceInfoDto;
+import com.yomahub.liteflow.util.JsonUtil;
 import org.apache.commons.lang.StringUtils;
-
 import java.util.*;
-
-import static com.yomahub.liteflow.util.JsonUtil.*;
 import static com.yomahub.liteflow.util.SerialsUtil.generateShortUUID;
 
 /**
@@ -73,7 +70,7 @@ public abstract class BaseNodeInstanceIdManageSpi implements NodeInstanceIdManag
 
         List<String> instanceIds = new ArrayList<>();
         for (int i = 1; i < instanceIdFile.size(); i++) {
-            List<InstanceInfoDto> instanceInfos = parseList(instanceIdFile.get(i), InstanceInfoDto.class);
+            List<InstanceInfoDto> instanceInfos = JsonUtil.parseList(instanceIdFile.get(i), InstanceInfoDto.class);
 
             for (InstanceInfoDto dto : instanceInfos) {
                 if (Objects.equals(dto.getNodeId(), nodeId)) {
@@ -133,24 +130,23 @@ public abstract class BaseNodeInstanceIdManageSpi implements NodeInstanceIdManag
      * 根据实例id获取 节点实例定位
      */
     @Override
-    public String getNodeLocationById(String chainId, String instanceId) {
+    public int getNodeLocationById(String chainId, String instanceId) {
         if (StringUtils.isBlank(chainId) || StringUtils.isBlank(instanceId)) {
-            return "";
+            return -1;
         }
         // 第一行为elMd5 第二行为实例id json格式信息
         List<String> instanceIdFile = readInstanceIdFile(chainId);
 
         for (int i = 1; i < instanceIdFile.size(); i++) {
-            List<InstanceInfoDto> instanceInfos = parseList(instanceIdFile.get(i), InstanceInfoDto.class);
+            List<InstanceInfoDto> instanceInfos = JsonUtil.parseList(instanceIdFile.get(i), InstanceInfoDto.class);
 
             for (InstanceInfoDto dto : instanceInfos) {
                 if (Objects.equals(dto.getInstanceId(), instanceId)) {
-                    return dto.getNodeId() + "(" + dto.getIndex() + ")";
+                    return dto.getIndex();
                 }
             }
         }
-
-        return "";
+        return -1;
     }
 
     /**
@@ -171,7 +167,7 @@ public abstract class BaseNodeInstanceIdManageSpi implements NodeInstanceIdManag
             // 文件存在,则直接读取
             List<InstanceInfoDto> instanceInfos = new ArrayList<>();
             for (int i = 1; i < instanceIdFile.size(); i++) {
-                instanceInfos = parseList(instanceIdFile.get(i), InstanceInfoDto.class);
+                instanceInfos = JsonUtil.parseList(instanceIdFile.get(i), InstanceInfoDto.class);
             }
             List<InstanceInfoDto> finalInstanceInfos = instanceInfos;
 

+ 1 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/NodeInstanceIdManageSpi.java

@@ -22,7 +22,7 @@ public interface NodeInstanceIdManageSpi {
     void writeInstanceIdFile(List<InstanceInfoDto> instanceIdList, String elMd5, String chainId);
 
     // 根据实例id获取 节点实例定位
-    String getNodeLocationById(String chainId, String instanceId);
+    int getNodeLocationById(String chainId, String instanceId);
 
     // 根据chainId instanceId返回Node节点信息
     Node getNodeByIdAndInstanceId(String chainId, String instanceId);

+ 158 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/meta/LiteflowMetaOperator.java

@@ -0,0 +1,158 @@
+package com.yomahub.liteflow.meta;
+
+import com.yomahub.liteflow.core.FlowExecutorHolder;
+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.instanceId.NodeInstanceIdManageSpiHolder;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * LiteFlow元数据统一操作类
+ * @since 2.13.0
+ * @author Bryan.Zhang
+ */
+public class LiteflowMetaOperator {
+
+    //--------------------------------------------Chain相关---------------------------------------------
+
+    /**
+     * 通过chainId获得Chain对象
+     * @param chainId Chain的Id
+     * @return Chain Chain对象
+     */
+    public static Chain getChain(String chainId){
+        return FlowBus.getChain(chainId);
+    }
+
+    /**
+     * 刷新所有的规则
+     * 可以手动重新从ruleSource指定的数据源进行刷新
+     * 此刷新操作将会刷新所有的规则
+     */
+    public static void reloadAllChain(){
+        FlowExecutorHolder.loadInstance().reloadRule();
+    }
+
+    /**
+     * 刷新某一个规则
+     * @param chainId chain的Id
+     * @param el 规则EL表达式
+     */
+    public static void reloadOneChain(String chainId, String el){
+        FlowBus.reloadChain(chainId, el);
+    }
+
+    /**
+     * 刷新某一个规则(带决策路由)
+     * @param chainId chain的Id
+     * @param el 规则EL表达式
+     * @param routeEl 决策路由EL表达式
+     */
+    public static void reloadOneChain(String chainId, String el, String routeEl){
+        FlowBus.reloadChain(chainId, el, routeEl);
+    }
+
+    /**
+     * 从元数据中卸载掉一个Chain
+     * @param chainId 需要卸载的chainId
+     */
+    public static void removeChain(String chainId){
+        FlowBus.removeChain(chainId);
+    }
+
+    /**
+     * 从元数据中卸载掉多个Chain
+     * @param chainIds 多个chainId
+     */
+    public static void removeChain(String... chainIds){
+        FlowBus.removeChain(chainIds);
+    }
+
+    //--------------------------------------------Node相关---------------------------------------------
+
+    /**
+     * 通过chainId获得这个chain中所有的Node
+     * @param chainId chain的Id
+     * @return 指定chain中的所有Node
+     */
+    public static List<Node> getNodes(String chainId){
+        return FlowBus.getNodesByChainId(chainId);
+    }
+
+    /**
+     * 通过chainId和nodeId获得Node列表
+     * @param chainId chain的Id
+     * @param nodeId 节点Id
+     * @return Node对象列表,一个节点在Chain里有可能出现多次
+     */
+    public static List<Node> getNodes(String chainId, String nodeId){
+        Chain chain = getChain(chainId);
+        if (chain == null){
+            return null;
+        }
+        return chain.getConditionList().stream().flatMap(
+                (Function<Condition, Stream<Node>>) condition -> condition.getAllNodeInCondition().stream()
+        ).filter(
+                node -> node.getId().equals(nodeId)
+        ).collect(Collectors.toList());
+    }
+
+    /**
+     * 通过chainId和nodeInstanceId去获得具体的Node节点
+     * 注意nodeInstance只有打开liteflow.enable-node-instance-id=true才会在Node对象中有
+     * @param chainId chain的Id
+     * @param nodeInstanceId Node节点的唯一Id
+     * @return Node节点对象
+     */
+    public static Node getNode(String chainId, String nodeInstanceId){
+        return NodeInstanceIdManageSpiHolder.getInstance().getNodeInstanceIdManageSpi().getNodeByIdAndInstanceId(chainId, nodeInstanceId);
+    }
+
+    /**
+     * 通过chainId,nodeId,index去获取具体的Node节点
+     * @param chainId chain的Id
+     * @param nodeId 节点的Id
+     * @param index 节点的序号下标,从0开始
+     * @return Node节点对象
+     */
+    public static Node getNode(String chainId, String nodeId, int index){
+        return NodeInstanceIdManageSpiHolder.getInstance().getNodeInstanceIdManageSpi().getNodeByIdAndIndex(chainId, nodeId, index);
+    }
+
+    /**
+     * 通过chainId,nodeInstanceId去获取这个nodeInstanceId在Chain中的位置
+     * 注意nodeInstance只有打开liteflow.enable-node-instance-id=true才会在Node对象中有
+     * @param chainId chain的Id
+     * @param nodeInstanceId Node的实例id
+     * @return nodeInstanceId在这个chain中的位置,从0开始
+     */
+    public static int getNodeIndex(String chainId, String nodeInstanceId){
+        return NodeInstanceIdManageSpiHolder.getInstance().getNodeInstanceIdManageSpi().getNodeLocationById(chainId, nodeInstanceId);
+    }
+
+    /**
+     * 通过chainId,nodeId去获取这个节点的所有的instanceId
+     * 注意nodeInstance只有打开liteflow.enable-node-instance-id=true才会在Node对象中有
+     * @param chainId chain的Id
+     * @param nodeId Node的实例id
+     * @return 节点的instanceId列表
+     */
+    public static List<String> getNodeInstanceIds(String chainId, String nodeId){
+        return NodeInstanceIdManageSpiHolder.getInstance().getNodeInstanceIdManageSpi().getNodeInstanceIds(chainId, nodeId);
+    }
+
+    /**
+     * 刷新某一个脚本
+     * @param nodeId 节点Id
+     * @param script 刷新的脚本内容
+     */
+    public static void reloadScript(String nodeId, String script){
+        FlowBus.reloadScript(nodeId, script);
+    }
+}

+ 55 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/java/com/yomahub/liteflow/test/script/javaxpro/refresh/ScriptJavaxProRefreshELTest.java

@@ -0,0 +1,55 @@
+package com.yomahub.liteflow.test.script.javaxpro.refresh;
+
+import cn.hutool.core.io.FileUtil;
+import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.enums.NodeTypeEnum;
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
+import com.yomahub.liteflow.flow.FlowBus;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.slot.DefaultContext;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+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.junit.jupiter.SpringExtension;
+
+import javax.annotation.Resource;
+
+@ExtendWith(SpringExtension.class)
+@TestPropertySource(value = "classpath:/refresh/application.properties")
+@SpringBootTest(classes = ScriptJavaxProRefreshELTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.script.javaxpro.refresh.cmp" })
+public class ScriptJavaxProRefreshELTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testRefresh1() {
+        String scriptContent = FileUtil.readUtf8String("refresh/s1.java");
+        LiteFlowNodeBuilder.createScriptNode().setId("s1")
+                .setScript(scriptContent)
+                .setLanguage(ScriptTypeEnum.JAVA.getDisplayName())
+                .build();
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", null, DefaultContext.class);
+        DefaultContext context = response.getFirstContextBean();
+        Assertions.assertTrue(response.isSuccess());
+        Assertions.assertEquals("1", context.getData("testFlag"));
+
+        //改写脚本
+        scriptContent = FileUtil.readUtf8String("refresh/s1_update.java");
+        FlowBus.reloadScript("s1", scriptContent);
+        response = flowExecutor.execute2Resp("chain1", null, DefaultContext.class);
+        context = response.getFirstContextBean();
+        Assertions.assertTrue(response.isSuccess());
+        Assertions.assertEquals("2", context.getData("testFlag"));
+
+    }
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/java/com/yomahub/liteflow/test/script/javaxpro/refresh/cmp/ACmp.java

@@ -0,0 +1,21 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.script.javaxpro.refresh.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeComponent;
+
+@LiteflowComponent("a")
+public class ACmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("ACmp executed!");
+	}
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/java/com/yomahub/liteflow/test/script/javaxpro/refresh/cmp/BCmp.java

@@ -0,0 +1,21 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.script.javaxpro.refresh.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeComponent;
+
+@LiteflowComponent("b")
+public class BCmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("BCmp executed!");
+	}
+
+}

+ 2 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/resources/refresh/application.properties

@@ -0,0 +1,2 @@
+liteflow.rule-source=refresh/flow.xml
+liteflow.parse-mode=PARSE_ONE_ON_FIRST_EXEC

+ 8 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/resources/refresh/flow.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE flow PUBLIC  "liteflow" "liteflow.dtd">
+<flow>
+    <chain name="chain1">
+        THEN(a,s1,b);
+    </chain>
+
+</flow>

+ 12 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/resources/refresh/s1.java

@@ -0,0 +1,12 @@
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.slot.DefaultContext;
+
+public class Demo extends NodeComponent {
+
+    @Override
+    public void process() {
+        DefaultContext context = this.getFirstContextBean();
+        context.setData("testFlag","1");
+    }
+
+}

+ 12 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javaxpro-springboot/src/test/resources/refresh/s1_update.java

@@ -0,0 +1,12 @@
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.slot.DefaultContext;
+
+public class Demo extends NodeComponent {
+
+    @Override
+    public void process() {
+        DefaultContext context = this.getFirstContextBean();
+        context.setData("testFlag","2");
+    }
+
+}

+ 1 - 1
liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/instanceIds/InstanceIdELSpringTest.java

@@ -86,7 +86,7 @@ public class InstanceIdELSpringTest extends BaseTest {
         NodeInstanceIdManageSpi nodeInstanceIdManageSpi = NodeInstanceIdManageSpiHolder.getInstance().getNodeInstanceIdManageSpi();
 
         for (int i = 0; i < strings.size(); i++) {
-            Assertions.assertEquals(nodeInstanceIdManageSpi.getNodeLocationById("chain2", strings.get(i)), "a(" + i + ")");
+            Assertions.assertEquals(nodeInstanceIdManageSpi.getNodeLocationById("chain2", strings.get(i)), i);
         }
 
         System.out.println(executeStepStrWithInstanceId);

+ 1 - 1
liteflow-testcase-el/liteflow-testcase-el-sql-springboot/src/test/java/com/yomahub/liteflow/test/sqlInstanceId/SQLWithXmlELInstanceIdSpringbootTest.java

@@ -70,7 +70,7 @@ public class SQLWithXmlELInstanceIdSpringbootTest extends BaseTest {
 
         String[] nodes = new String[]{"c", "b", "a"};
         for (int i = 0; i < strings.size(); i++) {
-            Assertions.assertEquals(nodeInstanceIdManageSpi.getNodeLocationById("r_chain4", strings.get(i)), nodes[i] + "(0)");
+            Assertions.assertEquals(nodeInstanceIdManageSpi.getNodeLocationById("r_chain4", strings.get(i)), 0);
         }
 
         HashSet<String> hashSet = Sets.newHashSet(strings);