Procházet zdrojové kódy

Merge branch 'refs/heads/dev'

everywhere.z před 1 rokem
rodič
revize
d4e464eb1a
100 změnil soubory, kde provedl 2752 přidání a 201 odebrání
  1. 12 0
      liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowFact.java
  2. 9 2
      liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java
  3. 4 0
      liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java
  4. 39 14
      liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java
  5. 73 6
      liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/DeclComponentProxy.java
  6. 13 1
      liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/MethodWrapBean.java
  7. 47 0
      liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ParameterWrapBean.java
  8. 3 1
      liteflow-core/src/main/java/com/yomahub/liteflow/enums/ScriptTypeEnum.java
  9. 26 0
      liteflow-core/src/main/java/com/yomahub/liteflow/exception/ParameterFactException.java
  10. 10 0
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Chain.java
  11. 0 23
      liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/NodeConvertHelper.java
  12. 13 4
      liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java
  13. 2 1
      liteflow-core/src/main/java/com/yomahub/liteflow/util/JsonUtil.java
  14. 4 1
      liteflow-core/src/main/resources/dtd/liteflow.dtd
  15. 1 1
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/constant/SqlReadConstant.java
  16. 38 23
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/polling/AbstractSqlReadPollTask.java
  17. 3 3
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/polling/SqlReadPollTask.java
  18. 27 9
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/polling/impl/ChainReadPollTask.java
  19. 31 13
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/polling/impl/ScriptReadPollTask.java
  20. 9 12
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/AbstractSqlRead.java
  21. 3 2
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/SqlRead.java
  22. 11 9
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/SqlReadFactory.java
  23. 16 15
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/ChainRead.java
  24. 13 41
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/ScriptRead.java
  25. 44 0
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/vo/ChainVO.java
  26. 64 0
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/vo/ScriptVO.java
  27. 19 13
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/util/JDBCHelper.java
  28. 26 0
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/vo/SQLParserVO.java
  29. 28 0
      liteflow-script-plugin/liteflow-script-kotlin/pom.xml
  30. 15 0
      liteflow-script-plugin/liteflow-script-kotlin/src/main/java/com/yomahub/liteflow/script/kotlin/KotlinScriptExecutor.java
  31. 2 0
      liteflow-script-plugin/liteflow-script-kotlin/src/main/resources/META-INF/services/com.yomahub.liteflow.script.ScriptExecutor
  32. 1 0
      liteflow-script-plugin/pom.xml
  33. 4 2
      liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonPathContentParser.java
  34. 17 5
      liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringDeclComponentParser.java
  35. 24 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathELDeclMultiSpringbootTest.java
  36. 97 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/ProcessFactELDeclMultiSpringbootTest.java
  37. 43 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/cmp/CmpConfig.java
  38. 40 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Company.java
  39. 24 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo1Context.java
  40. 29 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo2Context.java
  41. 32 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo3Context.java
  42. 29 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/TestContext.java
  43. 53 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/User.java
  44. 1 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/processFact/application.properties
  45. 18 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/processFact/flow.xml
  46. 24 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathELDeclSpringbootTest.java
  47. 97 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/ProcessFactELDeclSpringbootTest.java
  48. 28 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/cmp/ACmp.java
  49. 28 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/cmp/BCmp.java
  50. 27 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/cmp/CCmp.java
  51. 27 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/cmp/DCmp.java
  52. 40 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Company.java
  53. 24 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo1Context.java
  54. 29 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo2Context.java
  55. 32 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo3Context.java
  56. 29 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/TestContext.java
  57. 53 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/User.java
  58. 1 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/processFact/application.properties
  59. 18 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/processFact/flow.xml
  60. 24 0
      liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathTest.java
  61. 66 0
      liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/java/com/yomahub/liteflow/test/namespace/RouteSpringbootNamespaceTest.java
  62. 20 0
      liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/java/com/yomahub/liteflow/test/namespace/cmp/ACmp.java
  63. 21 0
      liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/java/com/yomahub/liteflow/test/namespace/cmp/BCmp.java
  64. 13 0
      liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/java/com/yomahub/liteflow/test/namespace/cmp/R1.java
  65. 13 0
      liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/java/com/yomahub/liteflow/test/namespace/cmp/R2.java
  66. 1 0
      liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/resources/namespace/application.properties
  67. 30 0
      liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/resources/namespace/flow.el.xml
  68. 32 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/pom.xml
  69. 24 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/BaseTest.java
  70. 36 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/cmpdata/LiteFlowCmpDataKotlinScriptELTest.java
  71. 22 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/cmpdata/cmp/ACmp.java
  72. 91 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/common/LiteFlowKotlinScriptCommonELTest.java
  73. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/common/cmp/ACmp.java
  74. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/common/cmp/BCmp.java
  75. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/common/cmp/CCmp.java
  76. 57 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/LiteFlowScriptContextbeanKotlinELTest.java
  77. 28 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/bean/CheckContext.java
  78. 37 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/bean/Order2Context.java
  79. 40 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/bean/OrderContext.java
  80. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/cmp/ACmp.java
  81. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/cmp/BCmp.java
  82. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/cmp/CCmp.java
  83. 37 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/meta/LiteflowKotlinScriptMetaELTest.java
  84. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/meta/cmp/ACmp.java
  85. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/meta/cmp/BCmp.java
  86. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/meta/cmp/CCmp.java
  87. 48 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/refresh/LiteflowKotlinScriptRefreshELTest.java
  88. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/refresh/cmp/ACmp.java
  89. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/refresh/cmp/BCmp.java
  90. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/refresh/cmp/CCmp.java
  91. 24 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/refresh/cmp/DCmp.java
  92. 114 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/remove/LiteFlowKotlinScriptRemoveELTest.java
  93. 103 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/LiteFlowScriptScriptbeanKotlinELTest.java
  94. 23 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/bean/DemoBean1.java
  95. 12 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/bean/DemoBean2.java
  96. 22 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/bean/DemoBean3.java
  97. 22 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/bean/DemoBean4.java
  98. 24 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/bean/DemoBean5.java
  99. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/cmp/ACmp.java
  100. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/cmp/BCmp.java

+ 12 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowFact.java

@@ -0,0 +1,12 @@
+package com.yomahub.liteflow.annotation;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+@Documented
+@Inherited
+public @interface LiteflowFact {
+
+    String value();
+}

+ 9 - 2
liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java

@@ -136,8 +136,7 @@ public class LiteFlowChainELBuilder {
 
 	public LiteFlowChainELBuilder setRoute(String routeEl){
 		if (StrUtil.isBlank(routeEl)) {
-			String errMsg = StrUtil.format("You have defined the label <route> but there is no el in the chain route[{}].", chain.getChainId());
-			throw new FlowSystemException(errMsg);
+			return this;
 		}
 		List<String> errorList = new ArrayList<>();
 		try {
@@ -233,6 +232,14 @@ public class LiteFlowChainELBuilder {
 		}
 	}
 
+	public LiteFlowChainELBuilder setNamespace(String nameSpace){
+		if (StrUtil.isBlank(nameSpace)) {
+			nameSpace = ChainConstant.DEFAULT_NAMESPACE;
+		}
+		this.chain.setNamespace(nameSpace);
+		return this;
+	}
+
 	/**
 	 * EL表达式校验
 	 * @param elStr EL表达式

+ 4 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java

@@ -32,6 +32,10 @@ public interface ChainConstant {
 
 	String LANGUAGE = "language";
 
+	String NAMESPACE = "namespace";
+
+	String DEFAULT_NAMESPACE = "default";
+
 	String VALUE = "value";
 
 	String ANY = "any";

+ 39 - 14
liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java

@@ -13,6 +13,7 @@ import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.lang.Tuple;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.*;
+import com.yomahub.liteflow.common.ChainConstant;
 import com.yomahub.liteflow.enums.ChainExecuteModeEnum;
 import com.yomahub.liteflow.enums.InnerChainTypeEnum;
 import com.yomahub.liteflow.enums.ParseModeEnum;
@@ -136,8 +137,8 @@ public class FlowExecutor {
 				// 查找对应的解析器
 				parser = FlowParserProvider.lookup(path);
 				parserNameSet.add(parser.getClass().getName());
-				// 替换掉前缀标识(如:xml:/json:),保留剩下的完整地址
-				path = ReUtil.replaceAll(path, PREFIX_FORMAT_CONFIG_REGEX, "");
+				// 替换掉前缀标识(如:xml:/json:),保留剩下的完整地址,并统一路径格式
+				path = ReUtil.replaceAll(path, PREFIX_FORMAT_CONFIG_REGEX, "").replace("\\", "/");
 				rulePathList.add(path);
 
 				// 支持多类型的配置文件,分别解析
@@ -283,7 +284,11 @@ public class FlowExecutor {
 	}
 
 	public List<LiteflowResponse> executeRouteChain(Object param, Class<?>... contextBeanClazzArray){
-		return this.executeWithRoute(param, null, contextBeanClazzArray, null);
+		return this.executeWithRoute(null, param, null, contextBeanClazzArray, null);
+	}
+
+	public List<LiteflowResponse> executeRouteChain(String namespace, Object param, Class<?>... contextBeanClazzArray){
+		return this.executeWithRoute(namespace, param, null, contextBeanClazzArray, null);
 	}
 
 	public LiteflowResponse execute2Resp(String chainId, Object param, Object... contextBeanArray) {
@@ -291,23 +296,35 @@ public class FlowExecutor {
 	}
 
 	public List<LiteflowResponse> executeRouteChain(Object param, Object... contextBeanArray){
-		return this.executeWithRoute(param, null, null, contextBeanArray);
+		return this.executeWithRoute(null, param, null, null, contextBeanArray);
+	}
+
+	public List<LiteflowResponse> executeRouteChain(String namespace, Object param, Object... contextBeanArray){
+		return this.executeWithRoute(namespace, param, null, null, contextBeanArray);
 	}
 
 	public LiteflowResponse execute2RespWithRid(String chainId, Object param, String requestId, Class<?>... contextBeanClazzArray) {
 		return this.execute2Resp(chainId, param, requestId, contextBeanClazzArray, null);
 	}
 
-	public List<LiteflowResponse> executeRouteChainWithRid(String chainId, Object param, String requestId, Class<?>... contextBeanClazzArray) {
-		return this.executeWithRoute(param, requestId, contextBeanClazzArray, null);
+	public List<LiteflowResponse> executeRouteChainWithRid(Object param, String requestId, Class<?>... contextBeanClazzArray) {
+		return this.executeWithRoute(null, param, requestId, contextBeanClazzArray, null);
+	}
+
+	public List<LiteflowResponse> executeRouteChainWithRid(String namespace, Object param, String requestId, Class<?>... contextBeanClazzArray) {
+		return this.executeWithRoute(namespace, param, requestId, contextBeanClazzArray, null);
 	}
 
 	public LiteflowResponse execute2RespWithRid(String chainId, Object param, String requestId, Object... contextBeanArray) {
 		return this.execute2Resp(chainId, param, requestId, null, contextBeanArray);
 	}
 
-	public List<LiteflowResponse> executeRouteChainWithRid(String chainId, Object param, String requestId, Object... contextBeanArray) {
-		return this.executeWithRoute(param, requestId, null, contextBeanArray);
+	public List<LiteflowResponse> executeRouteChainWithRid(Object param, String requestId, Object... contextBeanArray) {
+		return this.executeWithRoute(null, param, requestId, null, contextBeanArray);
+	}
+
+	public List<LiteflowResponse> executeRouteChainWithRid(String namespace, Object param, String requestId, Object... contextBeanArray) {
+		return this.executeWithRoute(namespace, param, requestId, null, contextBeanArray);
 	}
 
 	// 调用一个流程并返回Future<LiteflowResponse>,允许多上下文的传入
@@ -353,8 +370,8 @@ public class FlowExecutor {
 		return LiteflowResponse.newMainResponse(slot);
 	}
 
-	private List<LiteflowResponse> executeWithRoute(Object param, String requestId, Class<?>[] contextBeanClazzArray, Object[] contextBeanArray){
-		List<Slot> slotList = doExecuteWithRoute(param, requestId, contextBeanClazzArray, contextBeanArray);
+	private List<LiteflowResponse> executeWithRoute(String namespace, Object param, String requestId, Class<?>[] contextBeanClazzArray, Object[] contextBeanArray){
+		List<Slot> slotList = doExecuteWithRoute(namespace, param, requestId, contextBeanClazzArray, contextBeanArray);
 		return slotList.stream().map(LiteflowResponse::newMainResponse).collect(Collectors.toList());
 	}
 
@@ -522,15 +539,23 @@ public class FlowExecutor {
 		MonitorFile.getInstance().addMonitorFilePaths(fileAbsolutePath);
 	}
 
-	private List<Slot> doExecuteWithRoute(Object param, String requestId, Class<?>[] contextBeanClazzArray, Object[] contextBeanArray){
+	private List<Slot> doExecuteWithRoute(String namespace, Object param, String requestId, Class<?>[] contextBeanClazzArray, Object[] contextBeanArray){
 		if (FlowBus.needInit()) {
 			init(true);
 		}
 
-		List<Chain> routeChainList = FlowBus.getChainMap().values().stream().filter(chain -> chain.getRouteItem() != null).collect(Collectors.toList());
+		if (StrUtil.isBlank(namespace)){
+			namespace = ChainConstant.DEFAULT_NAMESPACE;
+		}
+
+		String finalNamespace = namespace;
+		List<Chain> routeChainList = FlowBus.getChainMap().values().stream()
+				.filter(chain -> chain.getNamespace().equals(finalNamespace))
+				.filter(chain -> chain.getRouteItem() != null).collect(Collectors.toList());
 
 		if (CollUtil.isEmpty(routeChainList)){
-			throw new RouteChainNotFoundException("cannot find any route chain");
+			String errorMsg = StrUtil.format("no route found for namespace[{}]", finalNamespace);
+			throw new RouteChainNotFoundException(errorMsg);
 		}
 
 		String finalRequestId;
@@ -601,7 +626,7 @@ public class FlowExecutor {
 			}
 		}).filter(Objects::nonNull).collect(Collectors.toList());
 
-		LOG.info("There are {} chains that matched the route.", resultSlotList.size());
+		LOG.info("chain namespace:[{}], total size:[{}], matched size:[{}]", namespace, routeChainList.size(), resultSlotList.size());
 
 		return resultSlotList;
 	}

+ 73 - 6
liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/DeclComponentProxy.java

@@ -1,17 +1,24 @@
 package com.yomahub.liteflow.core.proxy;
 
 import cn.hutool.core.exceptions.InvocationTargetRuntimeException;
+import cn.hutool.core.lang.Tuple;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ReflectUtil;
 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.yomahub.liteflow.annotation.LiteflowMethod;
 import com.yomahub.liteflow.annotation.LiteflowRetry;
 import com.yomahub.liteflow.core.NodeComponent;
 import com.yomahub.liteflow.exception.ComponentMethodDefineErrorException;
 import com.yomahub.liteflow.exception.LiteFlowException;
+import com.yomahub.liteflow.exception.ParameterFactException;
 import com.yomahub.liteflow.exception.ProxyException;
+import com.yomahub.liteflow.flow.element.Node;
 import com.yomahub.liteflow.log.LFLog;
 import com.yomahub.liteflow.log.LFLoggerManager;
+import com.yomahub.liteflow.slot.DataBus;
 import com.yomahub.liteflow.util.SerialsUtil;
 import net.bytebuddy.ByteBuddy;
 import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
@@ -21,7 +28,12 @@ import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -112,6 +124,10 @@ public class DeclComponentProxy {
                     .findFirst()
                     .orElse(null);
 
+            if (currentMethodWrapBean == null){
+                throw new ProxyException("currentMethodWrapBean is null");
+            }
+
             // 如果被代理的对象里有此标注标的方法,则调用此被代理的对象里的方法,如果没有,则调用父类里的方法
             // 进行检查,检查被代理的bean里是否第一个参数为NodeComponent这个类型的
             boolean checkFlag = currentMethodWrapBean.getMethod().getParameterTypes().length > 0
@@ -124,13 +140,13 @@ public class DeclComponentProxy {
                 throw new ComponentMethodDefineErrorException(errMsg);
             }
 
+
+            // 这里是针对于参数的处理
+            // 首先需要保证第一个参数是NodeComponent
+            // 其次需要针对于@LiteflowFact做处理
             try {
-                if (args != null && args.length > 0){
-                    Object[] wrapArgs = ArrayUtil.insert(args, 0, proxy);
-                    return ReflectUtil.invoke(declWarpBean.getRawBean(), currentMethodWrapBean.getMethod(), wrapArgs);
-                }else{
-                    return ReflectUtil.invoke(declWarpBean.getRawBean(), currentMethodWrapBean.getMethod(), proxy);
-                }
+                Object[] realArgs = loadMethodParameter(proxy, currentMethodWrapBean);
+                return ReflectUtil.invoke(declWarpBean.getRawBean(), currentMethodWrapBean.getMethod(), realArgs);
             }catch (InvocationTargetRuntimeException e) {
                 InvocationTargetException targetEx = (InvocationTargetException) e.getCause();
                 throw targetEx.getTargetException();
@@ -138,4 +154,55 @@ public class DeclComponentProxy {
         }
 
     }
+
+    private final ExpressRunner expressRunner = new ExpressRunner();
+
+    private Object[] loadMethodParameter(Object proxy, MethodWrapBean methodWrapBean){
+        NodeComponent thisNodeComponent = (NodeComponent) proxy;
+
+        return methodWrapBean.getParameterWrapBeanList().stream().map(parameterWrapBean -> {
+            // 如果参数是NodeComponent,那就返回proxy本身
+            if (parameterWrapBean.getParameterType().isAssignableFrom(NodeComponent.class)) {
+                return proxy;
+            }
+
+            // 如果没有@LiteflowFact标注,那么不处理,直接赋值null
+            if (parameterWrapBean.getFact() == null) {
+                return null;
+            }
+
+            // 把上下文数据转换成map形式的,key为别名,value为上下文
+            Map<String, Object> contextMap = DataBus.getSlot(thisNodeComponent.getSlotIndex()).getContextBeanList().stream().collect(
+                    Collectors.toMap(tuple -> tuple.get(0), tuple -> tuple.get(1))
+            );
+
+            List<String> errorList = new ArrayList<>();
+
+            Object result = null;
+            // 根据表达式去上下文里搜索相匹配的数据
+            for(Map.Entry<String, Object> entry : contextMap.entrySet()){
+                try{
+                    InstructionSet instructionSet = expressRunner.getInstructionSetFromLocalCache(entry.getKey() + "." + parameterWrapBean.getFact().value());
+                    DefaultContext<String, Object> context = new DefaultContext<>();
+                    context.put(entry.getKey(), entry.getValue());
+                    result = expressRunner.execute(instructionSet, context, errorList, false, false);
+                    if (result != null){
+                        break;
+                    }
+                }catch (Exception ignore){}
+            }
+
+            if (result == null){
+                try{
+                    // 如果没有搜到,那么尝试推断表达式是指定的上下文,按照指定上下文的方式去再获取
+                    InstructionSet instructionSet = expressRunner.getInstructionSetFromLocalCache("contextMap." + parameterWrapBean.getFact().value());
+                    DefaultContext<String, Object> context = new DefaultContext<>();
+                    context.put("contextMap", contextMap);
+                    result = expressRunner.execute(instructionSet, context, errorList, false, false);
+                }catch (Exception ignore){}
+            }
+
+            return result;
+        }).toArray();
+    }
 }

+ 13 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/MethodWrapBean.java

@@ -4,6 +4,7 @@ import com.yomahub.liteflow.annotation.LiteflowMethod;
 import com.yomahub.liteflow.annotation.LiteflowRetry;
 
 import java.lang.reflect.Method;
+import java.util.List;
 
 /**
  * LiteflowMethod的包装类
@@ -18,10 +19,13 @@ public class MethodWrapBean {
 
     private LiteflowRetry liteflowRetry;
 
-    public MethodWrapBean(Method method, LiteflowMethod liteflowMethod, LiteflowRetry liteflowRetry) {
+    private List<ParameterWrapBean> parameterWrapBeanList;
+
+    public MethodWrapBean(Method method, LiteflowMethod liteflowMethod, LiteflowRetry liteflowRetry, List<ParameterWrapBean> parameterWrapBeanList) {
         this.method = method;
         this.liteflowMethod = liteflowMethod;
         this.liteflowRetry = liteflowRetry;
+        this.parameterWrapBeanList = parameterWrapBeanList;
     }
 
     public Method getMethod() {
@@ -47,4 +51,12 @@ public class MethodWrapBean {
     public void setLiteflowRetry(LiteflowRetry liteflowRetry) {
         this.liteflowRetry = liteflowRetry;
     }
+
+    public List<ParameterWrapBean> getParameterWrapBeanList() {
+        return parameterWrapBeanList;
+    }
+
+    public void setParameterWrapBeanList(List<ParameterWrapBean> parameterWrapBeanList) {
+        this.parameterWrapBeanList = parameterWrapBeanList;
+    }
 }

+ 47 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ParameterWrapBean.java

@@ -0,0 +1,47 @@
+package com.yomahub.liteflow.core.proxy;
+
+import com.yomahub.liteflow.annotation.LiteflowFact;
+
+/**
+ * 声明式的包装类
+ * @author Bryan.Zhang
+ * @since 2.12.1
+ */
+public class ParameterWrapBean {
+
+    private Class<?> parameterType;
+
+    private LiteflowFact fact;
+
+    private int index;
+
+    public ParameterWrapBean(Class<?> parameterType, LiteflowFact fact, int index) {
+        this.parameterType = parameterType;
+        this.fact = fact;
+        this.index = index;
+    }
+
+    public Class<?> getParameterType() {
+        return parameterType;
+    }
+
+    public void setParameterType(Class<?> parameterType) {
+        this.parameterType = parameterType;
+    }
+
+    public LiteflowFact getFact() {
+        return fact;
+    }
+
+    public void setFact(LiteflowFact fact) {
+        this.fact = fact;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+}

+ 3 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/enums/ScriptTypeEnum.java

@@ -2,13 +2,15 @@ package com.yomahub.liteflow.enums;
 
 public enum ScriptTypeEnum {
 
+	CUSTOM("custom", "custom"),
 	GROOVY("groovy", "groovy"),
 	QLEXPRESS("qlexpress", "qlexpress"),
 	JS("javascript", "js"),
 	PYTHON("python", "python"),
 	LUA("luaj", "lua"),
 	AVIATOR("AviatorScript", "aviator"),
-	JAVA("java", "java");
+	JAVA("java", "java"),
+	KOTLIN("kotlin", "kotlin");
 
 	private String engineName;
 

+ 26 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/exception/ParameterFactException.java

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

+ 10 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Chain.java

@@ -40,6 +40,8 @@ public class Chain implements Executable{
 
 	private boolean isCompiled = true;
 
+	private String namespace;
+
 	public Chain(String chainName) {
 		this.chainId = chainName;
 	}
@@ -195,4 +197,12 @@ public class Chain implements Executable{
 	public void setCompiled(boolean compiled) {
 		isCompiled = compiled;
 	}
+
+	public String getNamespace() {
+		return namespace;
+	}
+
+	public void setNamespace(String namespace) {
+		this.namespace = namespace;
+	}
 }

+ 0 - 23
liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/NodeConvertHelper.java

@@ -15,29 +15,6 @@ import java.util.List;
  */
 public class NodeConvertHelper {
 
-    /*script节点的修改/添加*/
-    public static void changeScriptNode(NodeSimpleVO nodeSimpleVO, String newValue) {
-        // 有语言类型
-        if (StrUtil.isNotBlank(nodeSimpleVO.getLanguage())) {
-            LiteFlowNodeBuilder.createScriptNode()
-                    .setId(nodeSimpleVO.getNodeId())
-                    .setType(NodeTypeEnum.getEnumByCode(nodeSimpleVO.getType()))
-                    .setName(nodeSimpleVO.getName())
-                    .setScript(newValue)
-                    .setLanguage(nodeSimpleVO.getLanguage())
-                    .build();
-        }
-        // 没有语言类型
-        else {
-            LiteFlowNodeBuilder.createScriptNode()
-                    .setId(nodeSimpleVO.getNodeId())
-                    .setType(NodeTypeEnum.getEnumByCode(nodeSimpleVO.getType()))
-                    .setName(nodeSimpleVO.getName())
-                    .setScript(newValue)
-                    .build();
-        }
-    }
-
     public static NodeSimpleVO convert(String scriptKey){
         // 不需要去理解这串正则,就是一个匹配冒号的
         // 一定得是a:b,或是a:b:c...这种完整类型的字符串的

+ 13 - 4
liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java

@@ -1,5 +1,6 @@
 package com.yomahub.liteflow.parser.helper;
 
+import cn.hutool.core.util.BooleanUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.fasterxml.jackson.databind.JsonNode;
@@ -24,6 +25,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 import static com.yomahub.liteflow.common.ChainConstant.*;
 
@@ -205,7 +207,7 @@ public class ParserHelper {
             // 当存在<nodes>节点定义时,解析node节点
             if (flowJsonNode.get(FLOW).has(NODES)) {
                 Iterator<JsonNode> nodeIterator = flowJsonNode.get(FLOW).get(NODES).get(NODE).elements();
-                String id, name, clazz, script, type, file;
+                String id, name, clazz, script, type, file, language;
                 while ((nodeIterator.hasNext())) {
                     JsonNode nodeObject = nodeIterator.next();
                     id = nodeObject.get(ID).textValue();
@@ -214,6 +216,7 @@ public class ParserHelper {
                     type = nodeObject.hasNonNull(TYPE) ? nodeObject.get(TYPE).textValue() : null;
                     script = nodeObject.hasNonNull(VALUE) ? nodeObject.get(VALUE).textValue() : "";
                     file = nodeObject.hasNonNull(FILE) ? nodeObject.get(FILE).textValue() : "";
+                    language = nodeObject.hasNonNull(LANGUAGE) ? nodeObject.get(LANGUAGE).textValue() : "";
 
                     // 如果是禁用的,就不编译了
                     if (!getEnableByJsonNode(nodeObject)) {
@@ -226,7 +229,8 @@ public class ParserHelper {
                             .setClazz(clazz)
                             .setScript(script)
                             .setType(type)
-                            .setFile(file);
+                            .setFile(file)
+                            .setLanguage(language);
 
                     ParserHelper.buildNode(nodePropBean);
                 }
@@ -308,9 +312,11 @@ public class ParserHelper {
         // 构建chainBuilder
         String chainId = Optional.ofNullable(chainNode.get(ID)).orElse(chainNode.get(NAME)).textValue();
 
+        String namespace = chainNode.get(NAMESPACE) == null? DEFAULT_NAMESPACE : chainNode.get(NAMESPACE).textValue();
+
         JsonNode routeJsonNode = chainNode.get(ROUTE);
 
-        LiteFlowChainELBuilder builder = LiteFlowChainELBuilder.createChain().setChainId(chainId);
+        LiteFlowChainELBuilder builder = LiteFlowChainELBuilder.createChain().setChainId(chainId).setNamespace(namespace);
 
         // 如果有route这个标签,说明是决策表chain
         // 决策表链路必须有route和body这两个标签
@@ -337,9 +343,11 @@ public class ParserHelper {
         // 构建chainBuilder
         String chainId = Optional.ofNullable(e.attributeValue(ID)).orElse(e.attributeValue(NAME));
 
+        String namespace = StrUtil.blankToDefault(e.attributeValue(NAMESPACE), DEFAULT_NAMESPACE);
+
         Element routeElement = e.element(ROUTE);
 
-        LiteFlowChainELBuilder builder = LiteFlowChainELBuilder.createChain().setChainId(chainId);
+        LiteFlowChainELBuilder builder = LiteFlowChainELBuilder.createChain().setChainId(chainId).setNamespace(namespace);
 
         // 如果有route这个标签,说明是决策表chain
         // 决策表链路必须有route和body这两个标签
@@ -362,6 +370,7 @@ public class ParserHelper {
             }
         }
 
+
         builder.build();
     }
 

+ 2 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/util/JsonUtil.java

@@ -3,6 +3,7 @@ package com.yomahub.liteflow.util;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.yomahub.liteflow.exception.JsonProcessException;
@@ -27,6 +28,7 @@ public class JsonUtil {
 
 	static {
 		objectMapper.setTimeZone(TimeZone.getDefault());
+		objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
 	}
 
 	public static String toJsonString(Object object) {
@@ -71,5 +73,4 @@ public class JsonUtil {
 			throw new JsonProcessException(errMsg);
 		}
 	}
-
 }

+ 4 - 1
liteflow-core/src/main/resources/dtd/liteflow.dtd

@@ -13,10 +13,13 @@
         type (script|boolean_script|switch_script|for_script) #IMPLIED
         class CDATA #IMPLIED
         file CDATA #IMPLIED
-        language (qlexpress|groovy|js|python|lua|aviator|java) #IMPLIED
+        language (qlexpress|groovy|js|python|lua|aviator|java|kotlin) #IMPLIED
+        enable (true|false) #IMPLIED
         >
 <!ATTLIST chain
         id CDATA #IMPLIED
         name CDATA #IMPLIED
         extends CDATA #IMPLIED
+        enable (true|false) #IMPLIED
+        namespace CDATA #IMPLIED
         >

+ 1 - 1
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/constant/SqlReadConstant.java

@@ -16,7 +16,7 @@ public class SqlReadConstant {
 
     public static final String SCRIPT_SQL_PATTERN = "SELECT * FROM {} WHERE {}=?";
 
-    public static final String CHAIN_XML_PATTERN = "<chain name=\"{}\"><![CDATA[{}]]></chain>";
+    public static final String CHAIN_XML_PATTERN = "<chain id=\"{}\" namespace=\"{}\"><route><![CDATA[{}]]></route><body><![CDATA[{}]]></body></chain>";
 
     public static final String NODE_XML_PATTERN = "<nodes>{}</nodes>";
 

+ 38 - 23
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/polling/AbstractSqlReadPollTask.java

@@ -11,6 +11,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * sql 轮询任务抽象类,维护公共方法
@@ -19,11 +21,11 @@ import java.util.Set;
  * @author houxinyu
  * @since 2.11.1
  */
-public abstract class AbstractSqlReadPollTask implements SqlReadPollTask {
+public abstract class AbstractSqlReadPollTask<T> implements SqlReadPollTask<T> {
     private final Map<String/*唯一键*/, String/*data-xml的sha1值*/> DATA_SHA_MAP = new HashMap<>();
-    private final SqlRead read;
+    private final SqlRead<T> read;
 
-    public AbstractSqlReadPollTask(SqlRead read) {
+    public AbstractSqlReadPollTask(SqlRead<T> read) {
         this.read = read;
 
         if (!read.type().equals(type())) {
@@ -33,35 +35,34 @@ public abstract class AbstractSqlReadPollTask implements SqlReadPollTask {
 
     @Override
     public void execute() {
-        Map<String/*唯一键*/, String/*data-xml*/> newData = read.read();
+        List<T> dataList = read.read();
         // 新增或者更新的元素
-        Map<String, String> saveElementMap = new HashMap<>();
+        List<T> saveElementList = new ArrayList<>();
         // 删除的元素
-        List<String> deleteElementIds = new ArrayList<>();
+        List<String> deleteElementIds;
 
-        for (Map.Entry<String, String> entry : newData.entrySet()) {
-            String id = entry.getKey();
-            String element = entry.getValue();
-            String newSHA = DigestUtil.sha1Hex(element);
+        for (T data : dataList) {
+            String id = getKey(data);
+            String newSHA = getNeedSha1Value(data);
 
             // 新增
             // 如果封装的SHAMap中不存在该chain, 表示该元素为新增
             if (!DATA_SHA_MAP.containsKey(id)) {
-                saveElementMap.put(id, element);
+                saveElementList.add(data);
 
                 DATA_SHA_MAP.put(id, newSHA);
             }
             // 修改
             // SHA值发生变化,表示该元素的值已被修改,重新拉取变化的chain
             else if (!StrUtil.equals(newSHA, DATA_SHA_MAP.get(id))) {
-                saveElementMap.put(id, element);
+                saveElementList.add(data);
 
                 DATA_SHA_MAP.put(id, newSHA);
             }
         }
 
         Set<String> oldIdList = DATA_SHA_MAP.keySet();  // 旧的 id 列表
-        Set<String> newIdList = newData.keySet();       // 新的 id 列表
+        Set<String> newIdList = dataList.stream().map(this::getKey).collect(Collectors.toSet());       // 新的 id 列表
         // 计算单差集
         // 计算集合的单差集,即只返回【oldIdList】中有,但是【newIdList】中没有的元素,例如:
         //  subtractToList([1,2,3,4],[2,3,4,5]) -》 [1]
@@ -71,8 +72,8 @@ public abstract class AbstractSqlReadPollTask implements SqlReadPollTask {
             DATA_SHA_MAP.remove(id);
         }
 
-        if (CollUtil.isNotEmpty(saveElementMap)) {
-            doSave(saveElementMap);
+        if (CollUtil.isNotEmpty(saveElementList)) {
+            doSave(saveElementList);
         }
 
         if (CollUtil.isNotEmpty(deleteElementIds)) {
@@ -81,20 +82,34 @@ public abstract class AbstractSqlReadPollTask implements SqlReadPollTask {
     }
 
     @Override
-    public void initData(Map<String/*唯一键*/, String/*data-xml的数据*/> dataMap) {
-        DATA_SHA_MAP.putAll(shaMapValue(dataMap));
+    public void initData(List<T> dataList) {
+        DATA_SHA_MAP.putAll(shaValue(dataList));
     }
 
-    public abstract void doSave(Map<String, String> saveElementMap);
+    public abstract void doSave(List<T> saveElementList);
 
     public abstract void doDelete(List<String> deleteElementId);
 
-    private Map<String/*唯一键*/, String/*data-xml的sha1值*/> shaMapValue(Map<String, String> dataMap) {
+    private Map<String/*唯一键*/, String/*data-xml的sha1值*/> shaValue(List<T> dataList) {
         Map<String, String> result = new HashMap<>();
-        dataMap.forEach((k, v) -> {
-            result.put(k, DigestUtil.sha1Hex(v));
-        });
-
+        dataList.forEach(t -> result.put(getKey(t), DigestUtil.sha1Hex(getNeedSha1Value(t))));
         return result;
     }
+
+    private String getNeedSha1Value(T data) {
+        if (StrUtil.isBlank(getExtValue(data))) {
+            return DigestUtil.sha1Hex(getValue(data));
+        }else{
+            return DigestUtil.sha1Hex(getValue(data) + "|||" + getExtValue(data));
+        }
+    }
+
+    // 如果是chain,那就是返回chain的id,如果是script,那就返回script的id
+    protected abstract String getKey(T t);
+
+    // 如果是chain,那就返回EL,如果是script,那就返回脚本数据
+    protected abstract String getValue(T t);
+
+    // 如果是chain,那就返回route el,如果是script,这个不返回,因为script没有扩展value
+    protected abstract String getExtValue(T t);
 }

+ 3 - 3
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/polling/SqlReadPollTask.java

@@ -2,6 +2,7 @@ package com.yomahub.liteflow.parser.sql.polling;
 
 import com.yomahub.liteflow.parser.constant.ReadType;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -11,7 +12,7 @@ import java.util.Map;
  * @author houxinyu
  * @since 2.11.1
  */
-public interface SqlReadPollTask {
+public interface SqlReadPollTask<T> {
 
     /**
      * 执行
@@ -21,9 +22,8 @@ public interface SqlReadPollTask {
     /**
      * 初始化数据
      *
-     * @param dataMap 数据
      */
-    void initData(Map<String/*唯一键*/, String/*data-xml的数据*/> dataMap);
+    void initData(List<T> dataList);
 
     /**
      * 类型

+ 27 - 9
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/polling/impl/ChainReadPollTask.java

@@ -1,13 +1,16 @@
 package com.yomahub.liteflow.parser.sql.polling.impl;
 
+import cn.hutool.core.util.StrUtil;
 import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
 import com.yomahub.liteflow.flow.FlowBus;
 import com.yomahub.liteflow.parser.constant.ReadType;
 import com.yomahub.liteflow.parser.sql.polling.AbstractSqlReadPollTask;
 import com.yomahub.liteflow.parser.sql.read.SqlRead;
+import com.yomahub.liteflow.parser.sql.read.vo.ChainVO;
 
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
 
 /**
  * chain 读取任务
@@ -16,20 +19,20 @@ import java.util.Map;
  * @author houxinyu
  * @since 2.11.1
  */
-public class ChainReadPollTask extends AbstractSqlReadPollTask {
+public class ChainReadPollTask extends AbstractSqlReadPollTask<ChainVO> {
 
-    public ChainReadPollTask(SqlRead read) {
+    public ChainReadPollTask(SqlRead<ChainVO> read) {
         super(read);
     }
 
     @Override
-    public void doSave(Map<String, String> saveElementMap) {
-        for (Map.Entry<String, String> entry : saveElementMap.entrySet()) {
-            String chainName = entry.getKey();
-            String newData = entry.getValue();
-
-            LiteFlowChainELBuilder.createChain().setChainId(chainName).setEL(newData).build();
-        }
+    public void doSave(List<ChainVO> saveElementList) {
+        saveElementList.forEach(chainVO ->
+                LiteFlowChainELBuilder.createChain().setChainId(chainVO.getChainId())
+                .setRoute(chainVO.getRoute())
+                .setNamespace(chainVO.getNamespace())
+                .setEL(chainVO.getBody())
+                .build());
     }
 
     @Override
@@ -39,6 +42,21 @@ public class ChainReadPollTask extends AbstractSqlReadPollTask {
         }
     }
 
+    @Override
+    protected String getKey(ChainVO chainVO) {
+        return chainVO.getChainId();
+    }
+
+    @Override
+    protected String getValue(ChainVO chainVO) {
+        return chainVO.getBody();
+    }
+
+    @Override
+    protected String getExtValue(ChainVO chainVO) {
+        return chainVO.getRoute();
+    }
+
     @Override
     public ReadType type() {
         return ReadType.CHAIN;

+ 31 - 13
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/polling/impl/ScriptReadPollTask.java

@@ -1,13 +1,18 @@
 package com.yomahub.liteflow.parser.sql.polling.impl;
 
+import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
+import com.yomahub.liteflow.enums.NodeTypeEnum;
 import com.yomahub.liteflow.flow.FlowBus;
 import com.yomahub.liteflow.parser.constant.ReadType;
 import com.yomahub.liteflow.parser.helper.NodeConvertHelper;
 import com.yomahub.liteflow.parser.sql.polling.AbstractSqlReadPollTask;
 import com.yomahub.liteflow.parser.sql.read.SqlRead;
+import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO;
 
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
 
 /**
  * 脚本轮询任务
@@ -16,32 +21,45 @@ import java.util.Map;
  * @author houxinyu
  * @since 2.11.1
  */
-public class ScriptReadPollTask extends AbstractSqlReadPollTask {
-    public ScriptReadPollTask(SqlRead read) {
+public class ScriptReadPollTask extends AbstractSqlReadPollTask<ScriptVO> {
+    public ScriptReadPollTask(SqlRead<ScriptVO> read) {
         super(read);
     }
 
     @Override
-    public void doSave(Map<String, String> saveElementMap) {
-        for (Map.Entry<String, String> entry : saveElementMap.entrySet()) {
-            String scriptKey = entry.getKey();
-            String newData = entry.getValue();
-
-            NodeConvertHelper.NodeSimpleVO scriptVO = NodeConvertHelper.convert(scriptKey);
-            NodeConvertHelper.changeScriptNode(scriptVO, newData);
-        }
+    public void doSave(List<ScriptVO> saveElementList) {
+        saveElementList.forEach(scriptVO -> LiteFlowNodeBuilder.createScriptNode()
+                .setId(scriptVO.getNodeId())
+                .setType(NodeTypeEnum.getEnumByCode(scriptVO.getType()))
+                .setName(scriptVO.getName())
+                .setScript(scriptVO.getScript())
+                .setLanguage(scriptVO.getLanguage())
+                .build());
     }
 
     @Override
     public void doDelete(List<String> deleteElementId) {
         for (String id : deleteElementId) {
-            NodeConvertHelper.NodeSimpleVO scriptVO = NodeConvertHelper.convert(id);
-
             //  删除script
-            FlowBus.unloadScriptNode(scriptVO.getNodeId());
+            FlowBus.unloadScriptNode(id);
         }
     }
 
+    @Override
+    protected String getKey(ScriptVO scriptVO) {
+        return scriptVO.getNodeId();
+    }
+
+    @Override
+    protected String getValue(ScriptVO scriptVO) {
+        return scriptVO.getScript();
+    }
+
+    @Override
+    protected String getExtValue(ScriptVO scriptVO) {
+        return StrUtil.EMPTY;
+    }
+
     @Override
     public ReadType type() {
         return ReadType.SCRIPT;

+ 9 - 12
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/AbstractSqlRead.java

@@ -9,7 +9,9 @@ import com.yomahub.liteflow.parser.sql.util.LiteFlowJdbcUtil;
 import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
 
 import java.sql.*;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -20,7 +22,7 @@ import java.util.Map;
  * @author Bryan.Zhang
  * @since 2.11.1
  */
-public abstract class AbstractSqlRead implements SqlRead {
+public abstract class AbstractSqlRead<T> implements SqlRead<T> {
     public final SQLParserVO config;
     private static LFLog LOG = LFLoggerManager.getLogger(AbstractSqlRead.class);
 
@@ -29,10 +31,10 @@ public abstract class AbstractSqlRead implements SqlRead {
     }
 
     @Override
-    public Map<String/*规则唯一键*/, String/*规则内容*/> read() {
+    public List<T> read() {
         // 如果不需要读取直接返回
         if (!needRead()) {
-            return new HashMap<>();
+            return new ArrayList<>();
         }
 
         checkConfig();
@@ -40,7 +42,7 @@ public abstract class AbstractSqlRead implements SqlRead {
         // 如果允许,就打印 sql 语句
         logSqlIfEnable(sqlCmd);
 
-        Map<String/*规则唯一键*/, String/*规则*/> result = new HashMap<>();
+        List<T> result = new ArrayList<>();
         Connection conn = null;
         PreparedStatement stmt = null;
         ResultSet rs = null;
@@ -54,9 +56,6 @@ public abstract class AbstractSqlRead implements SqlRead {
             rs = stmt.executeQuery();
 
             while (rs.next()) {
-                String xml = buildXmlElement(rs);
-                String uniqueKey = buildXmlElementUniqueKey(rs);
-
                 if (hasEnableFiled()){
                     boolean enable = getEnableFiledValue(rs);
                     // 如果停用,直接跳过
@@ -64,7 +63,7 @@ public abstract class AbstractSqlRead implements SqlRead {
                         continue;
                     }
                 }
-                result.put(uniqueKey, xml);
+                result.add(parse(rs));
             }
         } catch (Exception e) {
             throw new ELSQLException(e.getMessage());
@@ -76,6 +75,8 @@ public abstract class AbstractSqlRead implements SqlRead {
         return result;
     }
 
+    protected abstract T parse(ResultSet rs) throws SQLException;
+
     /**
      * 是否包含启停字段
      */
@@ -88,10 +89,6 @@ public abstract class AbstractSqlRead implements SqlRead {
 
     public abstract String buildQuerySql();
 
-    public abstract String buildXmlElement(ResultSet rs) throws SQLException;
-
-    public abstract String buildXmlElementUniqueKey(ResultSet rs) throws SQLException;
-
     public abstract void checkConfig();
 
     /**

+ 3 - 2
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/SqlRead.java

@@ -2,6 +2,7 @@ package com.yomahub.liteflow.parser.sql.read;
 
 import com.yomahub.liteflow.parser.constant.ReadType;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -11,14 +12,14 @@ import java.util.Map;
  * @author houxinyu
  * @since 2.11.1
  */
-public interface SqlRead {
+public interface SqlRead<T> {
 
     /**
      * 读取
      *
      * @return 返回读取到的数据
      */
-    Map<String/*规则唯一键*/, String/*规则内容*/> read();
+    List<T> read();
 
     /**
      * 类型

+ 11 - 9
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/SqlReadFactory.java

@@ -19,8 +19,8 @@ import java.util.Map;
  * @since 2.11.1
  */
 public class SqlReadFactory {
-    private static final Map<ReadType, SqlRead> READ_MAP = new HashMap<>();
-    private static final Map<ReadType, SqlReadPollTask> POLL_TASK_MAP = new HashMap<>();
+    private static final Map<ReadType, SqlRead<?>> READ_MAP = new HashMap<>();
+    private static final Map<ReadType, SqlReadPollTask<?>> POLL_TASK_MAP = new HashMap<>();
 
     public static void registerRead(SQLParserVO config) {
         READ_MAP.put(ReadType.CHAIN, new ChainRead(config));
@@ -28,19 +28,21 @@ public class SqlReadFactory {
     }
 
     public static void registerSqlReadPollTask(ReadType readType) {
-        SqlRead sqlRead = getSqlRead(readType);
+        SqlRead<?> sqlRead = getSqlRead(readType);
         if (ReadType.CHAIN.equals(readType)) {
-            POLL_TASK_MAP.put(ReadType.CHAIN, new ChainReadPollTask(sqlRead));
+            POLL_TASK_MAP.put(ReadType.CHAIN, new ChainReadPollTask((ChainRead)sqlRead));
         } else if (ReadType.SCRIPT.equals(readType)) {
-            POLL_TASK_MAP.put(ReadType.SCRIPT, new ScriptReadPollTask(sqlRead));
+            POLL_TASK_MAP.put(ReadType.SCRIPT, new ScriptReadPollTask((ScriptRead)sqlRead));
         }
     }
 
-    public static SqlRead getSqlRead(ReadType readType) {
-        return READ_MAP.get(readType);
+    @SuppressWarnings("unchecked")
+    public static <T> SqlRead<T> getSqlRead(ReadType readType) {
+        return (SqlRead<T>)READ_MAP.get(readType);
     }
 
-    public static SqlReadPollTask getSqlReadPollTask(ReadType readType) {
-        return POLL_TASK_MAP.get(readType);
+    @SuppressWarnings("unchecked")
+    public static <T> SqlReadPollTask<T> getSqlReadPollTask(ReadType readType) {
+        return (SqlReadPollTask<T>)POLL_TASK_MAP.get(readType);
     }
 }

+ 16 - 15
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/ChainRead.java

@@ -5,6 +5,7 @@ import com.yomahub.liteflow.parser.constant.ReadType;
 import com.yomahub.liteflow.parser.constant.SqlReadConstant;
 import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
 import com.yomahub.liteflow.parser.sql.read.AbstractSqlRead;
+import com.yomahub.liteflow.parser.sql.read.vo.ChainVO;
 import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
 
 import java.sql.ResultSet;
@@ -17,12 +18,26 @@ import java.sql.SQLException;
  * @author houxinyu
  * @since 2.11.1
  */
-public class ChainRead extends AbstractSqlRead {
+public class ChainRead extends AbstractSqlRead<ChainVO> {
 
     public ChainRead(SQLParserVO config) {
         super(config);
     }
 
+    @Override
+    protected ChainVO parse(ResultSet rs) throws SQLException {
+        ChainVO chainVO = new ChainVO();
+        chainVO.setChainId(getStringFromRsWithCheck(rs, super.config.getChainNameField()));
+        chainVO.setBody(getStringFromRsWithCheck(rs, super.config.getElDataField()));
+        if (StrUtil.isNotBlank(super.config.getNamespaceField())){
+            chainVO.setNamespace(getStringFromRs(rs, super.config.getNamespaceField()));
+        }
+        if (StrUtil.isNotBlank(super.config.getRouteField())){
+            chainVO.setRoute(getStringFromRs(rs, super.config.getRouteField()));
+        }
+        return chainVO;
+    }
+
     @Override
     public boolean hasEnableFiled() {
         String chainEnableField = super.config.getChainEnableField();
@@ -70,20 +85,6 @@ public class ChainRead extends AbstractSqlRead {
         }
     }
 
-    @Override
-    public String buildXmlElement(ResultSet rs) throws SQLException {
-        String elDataField = super.config.getElDataField();
-
-        return getStringFromRs(rs, elDataField);
-    }
-
-    @Override
-    public String buildXmlElementUniqueKey(ResultSet rs) throws SQLException {
-        String chainNameField = super.config.getChainNameField();
-
-        return getStringFromRsWithCheck(rs, chainNameField);
-    }
-
     @Override
     public ReadType type() {
         return ReadType.CHAIN;

+ 13 - 41
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/ScriptRead.java

@@ -8,6 +8,7 @@ import com.yomahub.liteflow.parser.constant.ReadType;
 import com.yomahub.liteflow.parser.constant.SqlReadConstant;
 import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
 import com.yomahub.liteflow.parser.sql.read.AbstractSqlRead;
+import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO;
 import com.yomahub.liteflow.parser.sql.util.LiteFlowJdbcUtil;
 import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
 
@@ -24,12 +25,23 @@ import java.util.Objects;
  * @author houxinyu
  * @since 2.11.1
  */
-public class ScriptRead extends AbstractSqlRead {
+public class ScriptRead extends AbstractSqlRead<ScriptVO> {
 
     public ScriptRead(SQLParserVO config) {
         super(config);
     }
 
+    @Override
+    protected ScriptVO parse(ResultSet rs) throws SQLException {
+        ScriptVO scriptVO = new ScriptVO();
+        scriptVO.setNodeId(getStringFromRsWithCheck(rs, super.config.getScriptIdField()));
+        scriptVO.setName(getStringFromRs(rs, super.config.getScriptNameField()));
+        scriptVO.setType(getStringFromRsWithCheck(rs, super.config.getScriptTypeField()));
+        scriptVO.setLanguage(getStringFromRs(rs, super.config.getScriptLanguageField()));
+        scriptVO.setScript(getStringFromRsWithCheck(rs, super.config.getScriptDataField()));
+        return scriptVO;
+    }
+
     @Override
     public boolean hasEnableFiled() {
         String scriptEnableField = super.config.getScriptEnableField();
@@ -80,46 +92,6 @@ public class ScriptRead extends AbstractSqlRead {
         }
     }
 
-    @Override
-    public String buildXmlElement(ResultSet rs) throws SQLException {
-        String scriptDataField = super.config.getScriptDataField();
-
-        return getStringFromRs(rs, scriptDataField);
-
-    }
-
-    @Override
-    public String buildXmlElementUniqueKey(ResultSet rs) throws SQLException {
-        String scriptIdField = super.config.getScriptIdField();
-        String scriptNameField = super.config.getScriptNameField();
-        String scriptTypeField = super.config.getScriptTypeField();
-        String scriptLanguageField = super.config.getScriptLanguageField();
-
-        String id = getStringFromRsWithCheck(rs, scriptIdField);
-        String name = getStringFromRsWithCheck(rs, scriptNameField);
-        String type = getStringFromRsWithCheck(rs, scriptTypeField);
-        String language = withLanguage() ? getStringFromRs(rs, scriptLanguageField) : null;
-
-        NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type);
-        if (Objects.isNull(nodeTypeEnum)) {
-            throw new ELSQLException(StrUtil.format("Invalid type value[{}]", type));
-        }
-
-        if (!nodeTypeEnum.isScript()) {
-            throw new ELSQLException(StrUtil.format("The type value[{}] is not a script type", type));
-        }
-
-        if (withLanguage() && !ScriptTypeEnum.checkScriptType(language)) {
-            throw new ELSQLException(StrUtil.format("The language value[{}] is invalid", language));
-        }
-        List<String> keys = CollUtil.newArrayList(id, type, name);
-        if (StrUtil.isNotBlank(language)) {
-            keys.add(language);
-        }
-
-        return StrUtil.join(StrUtil.COLON, keys);
-    }
-
     @Override
     public boolean needRead() {
         if (StrUtil.isBlank(super.config.getScriptTableName())) {

+ 44 - 0
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/vo/ChainVO.java

@@ -0,0 +1,44 @@
+package com.yomahub.liteflow.parser.sql.read.vo;
+
+public class ChainVO {
+
+    private String chainId;
+
+    private String route;
+
+    private String namespace;
+
+    private String body;
+
+    public String getChainId() {
+        return chainId;
+    }
+
+    public void setChainId(String chainId) {
+        this.chainId = chainId;
+    }
+
+    public String getRoute() {
+        return route;
+    }
+
+    public void setRoute(String route) {
+        this.route = route;
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String body) {
+        this.body = body;
+    }
+}

+ 64 - 0
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/vo/ScriptVO.java

@@ -0,0 +1,64 @@
+package com.yomahub.liteflow.parser.sql.read.vo;
+
+public class ScriptVO {
+
+    private String nodeId;
+
+    private String type;
+
+    private String name;
+
+    private String language;
+
+    private Boolean enable;
+
+    private String script;
+
+    public String getNodeId() {
+        return nodeId;
+    }
+
+    public void setNodeId(String nodeId) {
+        this.nodeId = nodeId;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    public String getScript() {
+        return script;
+    }
+
+    public void setScript(String script) {
+        this.script = script;
+    }
+}

+ 19 - 13
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/util/JDBCHelper.java

@@ -11,9 +11,12 @@ import com.yomahub.liteflow.parser.constant.ReadType;
 
 import com.yomahub.liteflow.parser.helper.NodeConvertHelper;
 import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
+import com.yomahub.liteflow.parser.sql.polling.SqlReadPollTask;
 import com.yomahub.liteflow.parser.sql.read.AbstractSqlRead;
 import com.yomahub.liteflow.parser.sql.read.SqlRead;
 import com.yomahub.liteflow.parser.sql.read.SqlReadFactory;
+import com.yomahub.liteflow.parser.sql.read.vo.ChainVO;
+import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO;
 import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
 import org.apache.commons.lang.StringUtils;
 
@@ -87,30 +90,30 @@ public class JDBCHelper {
      * @return 数据内容
      */
     public String getContent() {
-        SqlRead chainRead = SqlReadFactory.getSqlRead(ReadType.CHAIN);
-        SqlRead scriptRead = SqlReadFactory.getSqlRead(ReadType.SCRIPT);
+        SqlRead<ChainVO> chainRead = SqlReadFactory.getSqlRead(ReadType.CHAIN);
+        SqlRead<ScriptVO> scriptRead = SqlReadFactory.getSqlRead(ReadType.SCRIPT);
 
         // 获取 chain 数据
-        Map<String, String> chainMap = chainRead.read();
+        List<ChainVO> chainVOList = chainRead.read();
         List<String> chainList = new ArrayList<>();
 
-        chainMap.entrySet().stream()
-                .filter(entry -> StrUtil.isNotBlank(entry.getValue()))
-                .forEach(
-                    entry -> chainList.add(StrUtil.format(CHAIN_XML_PATTERN, XmlUtil.escape(entry.getKey()), entry.getValue()))
-                );
+        chainVOList.forEach(
+                chainVO -> chainList.add(StrUtil.format(CHAIN_XML_PATTERN, XmlUtil.escape(chainVO.getChainId()), StrUtil.emptyIfNull(chainVO.getNamespace()), StrUtil.emptyIfNull(chainVO.getRoute()), chainVO.getBody()))
+        );
+
 
         String chainsContent = CollUtil.join(chainList, StrUtil.EMPTY);
 
         // 获取脚本数据
-        Map<String, String> scriptMap = scriptRead.read();
+        List<ScriptVO> scriptVOList = scriptRead.read();
         List<String> scriptList = new ArrayList<>();
-        scriptMap.forEach((scriptKey, elData) -> {
-            NodeConvertHelper.NodeSimpleVO scriptVO = NodeConvertHelper.convert(scriptKey);
+
+        scriptVOList.forEach(scriptVO -> {
             String id = scriptVO.getNodeId();
             String name = scriptVO.getName();
             String type = scriptVO.getType();
             String language = scriptVO.getLanguage();
+            String elData = scriptVO.getScript();
 
             if (StringUtils.isNotBlank(scriptVO.getLanguage())) {
                 scriptList.add(StrUtil.format(NODE_ITEM_WITH_LANGUAGE_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, language, elData));
@@ -118,11 +121,14 @@ public class JDBCHelper {
                 scriptList.add(StrUtil.format(NODE_ITEM_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, elData));
             }
         });
+
         String nodesContent = StrUtil.format(NODE_XML_PATTERN, CollUtil.join(scriptList, StrUtil.EMPTY));
 
         // 初始化轮询任务
-        SqlReadFactory.getSqlReadPollTask(ReadType.CHAIN).initData(chainMap);
-        SqlReadFactory.getSqlReadPollTask(ReadType.SCRIPT).initData(scriptMap);
+        SqlReadPollTask<ChainVO> sqlReadPollTask4Chain = SqlReadFactory.getSqlReadPollTask(ReadType.CHAIN);
+        sqlReadPollTask4Chain.initData(chainVOList);
+        SqlReadPollTask<ScriptVO> sqlReadPollTask4Script = SqlReadFactory.getSqlReadPollTask(ReadType.SCRIPT);
+        sqlReadPollTask4Script.initData(scriptVOList);
         return StrUtil.format(XML_PATTERN, nodesContent, chainsContent);
     }
 

+ 26 - 0
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/vo/SQLParserVO.java

@@ -56,6 +56,16 @@ public class SQLParserVO {
      */
     private String elDataField = "el_data";
 
+    /**
+     * 决策路由字段
+     */
+    private String routeField;
+
+    /**
+     * 命名空间字段
+     */
+    private String namespaceField;
+
     /**
      * 是否启动某一条chain
      */
@@ -310,4 +320,20 @@ public class SQLParserVO {
     public boolean hasEnableField() {
         return StrUtil.isNotBlank(chainEnableField) || StrUtil.isNotBlank(scriptEnableField);
     }
+
+    public String getRouteField() {
+        return routeField;
+    }
+
+    public void setRouteField(String routeField) {
+        this.routeField = routeField;
+    }
+
+    public String getNamespaceField() {
+        return namespaceField;
+    }
+
+    public void setNamespaceField(String namespaceField) {
+        this.namespaceField = namespaceField;
+    }
 }

+ 28 - 0
liteflow-script-plugin/liteflow-script-kotlin/pom.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>liteflow-script-plugin</artifactId>
+        <groupId>com.yomahub</groupId>
+        <version>${revision}</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>liteflow-script-kotlin</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.yomahub</groupId>
+            <artifactId>liteflow-core</artifactId>
+            <version>${revision}</version>
+            <optional>true</optional>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jetbrains.kotlin</groupId>
+            <artifactId>kotlin-scripting-jsr223</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 15 - 0
liteflow-script-plugin/liteflow-script-kotlin/src/main/java/com/yomahub/liteflow/script/kotlin/KotlinScriptExecutor.java

@@ -0,0 +1,15 @@
+package com.yomahub.liteflow.script.kotlin;
+
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
+import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
+
+/**
+ * Kotlin脚本执行器
+ * @author DaleLee
+ */
+public class KotlinScriptExecutor extends JSR223ScriptExecutor {
+    @Override
+    public ScriptTypeEnum scriptType() {
+        return ScriptTypeEnum.KOTLIN;
+    }
+}

+ 2 - 0
liteflow-script-plugin/liteflow-script-kotlin/src/main/resources/META-INF/services/com.yomahub.liteflow.script.ScriptExecutor

@@ -0,0 +1,2 @@
+# Kotlin的实现
+com.yomahub.liteflow.script.kotlin.KotlinScriptExecutor

+ 1 - 0
liteflow-script-plugin/pom.xml

@@ -23,6 +23,7 @@
         <module>liteflow-script-lua</module>
         <module>liteflow-script-aviator</module>
         <module>liteflow-script-java</module>
+        <module>liteflow-script-kotlin</module>
     </modules>
 
 </project>

+ 4 - 2
liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonPathContentParser.java

@@ -8,6 +8,7 @@ import cn.hutool.core.util.CharsetUtil;
 import cn.hutool.core.util.StrUtil;
 import com.yomahub.liteflow.exception.ConfigErrorException;
 import com.yomahub.liteflow.spi.PathContentParser;
+import com.yomahub.liteflow.util.PathMatchUtil;
 import org.noear.solon.Utils;
 
 import java.io.File;
@@ -47,9 +48,10 @@ public class SolonPathContentParser implements PathContentParser {
 		if (CollectionUtil.isEmpty(pathList)) {
 			throw new ConfigErrorException("rule source must not be null");
 		}
-
+		List<String> absolutePathList = PathMatchUtil.searchAbsolutePath(pathList);
 		List<URL> allResource = new ArrayList<>();
-		for (String path : pathList) {
+
+		for (String path : absolutePathList) {
 			// 如果 path 是绝对路径且这个文件存在时,我们认为这是一个本地文件路径,而并非classpath路径
 			if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)) {
 				allResource.add(new File(path).toURI().toURL());

+ 17 - 5
liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringDeclComponentParser.java

@@ -1,24 +1,27 @@
 package com.yomahub.liteflow.spi.spring;
 
 import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.util.ReflectUtil;
 import cn.hutool.core.util.StrUtil;
-import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
-import com.yomahub.liteflow.annotation.LiteflowComponent;
-import com.yomahub.liteflow.annotation.LiteflowMethod;
-import com.yomahub.liteflow.annotation.LiteflowRetry;
+import com.yomahub.liteflow.annotation.*;
 import com.yomahub.liteflow.annotation.util.AnnoUtil;
 import com.yomahub.liteflow.core.proxy.DeclWarpBean;
 import com.yomahub.liteflow.core.proxy.MethodWrapBean;
+import com.yomahub.liteflow.core.proxy.ParameterWrapBean;
 import com.yomahub.liteflow.enums.NodeTypeEnum;
 import com.yomahub.liteflow.exception.CmpDefinitionException;
 import com.yomahub.liteflow.spi.DeclComponentParser;
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.beans.factory.support.RootBeanDefinition;
 import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Parameter;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 /**
  * Spring环境声明式组件解析器实现
@@ -73,7 +76,16 @@ public class SpringDeclComponentParser implements DeclComponentParser {
                 nodeType = liteflowMethod.nodeType();
             }
 
-            return new DeclInfo(currNodeId, currNodeName, nodeType, method.getDeclaringClass(), new MethodWrapBean(method, liteflowMethod, liteflowRetry));
+
+            Parameter[] parameters = method.getParameters();
+            List<ParameterWrapBean> parameterList = IntStream.range(0, parameters.length).boxed().map(index -> {
+                Parameter parameter = parameters[index];
+                return new ParameterWrapBean(parameter.getType(), AnnotationUtil.getAnnotation(parameter, LiteflowFact.class), index);
+            }).collect(Collectors.toList());
+
+
+
+            return new DeclInfo(currNodeId, currNodeName, nodeType, method.getDeclaringClass(), new MethodWrapBean(method, liteflowMethod, liteflowRetry, parameterList));
         }).filter(declInfo -> StrUtil.isNotBlank(declInfo.getNodeId())).collect(Collectors.groupingBy(DeclInfo::getNodeId));
 
         return definitionMap.entrySet().stream().map(entry -> {

+ 24 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathELDeclMultiSpringbootTest.java

@@ -13,6 +13,7 @@ import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIf;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.slf4j.Logger;
@@ -63,6 +64,29 @@ public class AbsoluteConfigPathELDeclMultiSpringbootTest extends BaseTest {
 		});
 	}
 
+	@Test
+	@EnabledIf("isWindows")
+	public void testAbsPath() throws Exception{
+		Assertions.assertTrue(() -> {
+			LiteflowConfig config = LiteflowConfigGetter.get();
+			config.setRuleSource(StrUtil.format("{}\\sub\\**\\*.xml",rootDir));
+			flowExecutor.reloadRule();
+			return flowExecutor.execute2Resp("chain1", "arg").isSuccess();
+		});
+	}
+
+	public static boolean isWindows() {
+		try {
+			String osName = System.getProperty("os.name");
+			if (osName.isEmpty()) return false;
+			else {
+				return osName.contains("Windows");
+			}
+		} catch (Exception e) {
+			return false;
+		}
+	}
+
 	@BeforeAll
 	public static void createFiles() {
 		rootDir = FileUtil.getAbsolutePath(ResourceUtil.getResource("").getPath());

+ 97 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/ProcessFactELDeclMultiSpringbootTest.java

@@ -0,0 +1,97 @@
+package com.yomahub.liteflow.test.processFact;
+
+import cn.hutool.core.date.DateUtil;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import com.yomahub.liteflow.test.processFact.context.*;
+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;
+
+/**
+ * process方法上的fact映射参数测试
+ * @author Bryan.Zhang
+ */
+@ExtendWith(SpringExtension.class)
+@TestPropertySource(value = "classpath:/processFact/application.properties")
+@SpringBootTest(classes = ProcessFactELDeclMultiSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.processFact.cmp"})
+public class ProcessFactELDeclMultiSpringbootTest extends BaseTest {
+
+	@Resource
+	private FlowExecutor flowExecutor;
+
+	// 最基本的情况
+	@Test
+	public void testFact1() throws Exception {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", createContext());
+		Assertions.assertTrue(response.isSuccess());
+		TestContext context = response.getContextBean(TestContext.class);
+		Assertions.assertEquals("jack", context.getUser().getName());
+	}
+
+	// 多上下文自动搜寻
+	@Test
+	public void testFact2() throws Exception {
+		TestContext testContext = createContext();
+		Demo1Context demo1Context = new Demo1Context();
+		demo1Context.setData1("xxxx");
+		demo1Context.setData2(99);
+
+		LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg", demo1Context, testContext);
+		Assertions.assertTrue(response.isSuccess());
+		TestContext context = response.getContextBean(TestContext.class);
+		Assertions.assertEquals(20, context.getUser().getCompany().getHeadCount());
+	}
+
+	// 多上下文都有user,指定上下文中的user
+	@Test
+	public void testFact3() throws Exception {
+		TestContext testContext = createContext();
+		Demo2Context demo2Context = createDemo2Context();
+
+		LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg", testContext, demo2Context);
+		Assertions.assertTrue(response.isSuccess());
+		Demo2Context context = response.getContextBean(Demo2Context.class);
+		Assertions.assertEquals("rose", context.getUser().getName());
+	}
+
+	// 多上下文都有user,指定上下文中的user
+	@Test
+	public void testFact4() throws Exception {
+		Demo3Context demo3Context = createDemo3Context();
+
+		LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg", demo3Context);
+		Assertions.assertTrue(response.isSuccess());
+		Demo3Context context = response.getContextBean(Demo3Context.class);
+		Assertions.assertEquals("jelly", context.getUser().getName());
+	}
+
+	private TestContext createContext(){
+		Company company = new Company("XXX有限公司", "黄河路34号303室", 400);
+		User user = new User("张三", 18, DateUtil.parseDate("1990-08-20"), company);
+        return new TestContext(user, "this is data");
+	}
+
+	private Demo2Context createDemo2Context(){
+		Company company = new Company("XXX有限公司", "和平路12号101室", 600);
+		User user = new User("李四", 28, DateUtil.parseDate("1990-06-01"), company);
+		return new Demo2Context("xxx", user);
+	}
+
+	private Demo3Context createDemo3Context(){
+		Company company = new Company("XXX有限公司", "和平路12号101室", 600);
+		User user = new User("王五", 28, DateUtil.parseDate("1990-06-01"), company);
+		return new Demo3Context("xxx", user);
+	}
+
+}

+ 43 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/cmp/CmpConfig.java

@@ -0,0 +1,43 @@
+package com.yomahub.liteflow.test.processFact.cmp;
+
+import cn.hutool.core.collection.ConcurrentHashSet;
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.annotation.LiteflowFact;
+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.processFact.context.Company;
+import com.yomahub.liteflow.test.processFact.context.User;
+import org.springframework.stereotype.Component;
+
+@LiteflowComponent
+public class CmpConfig {
+
+    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeType = NodeTypeEnum.COMMON, nodeId = "a")
+    public void processA(NodeComponent bindCmp,
+                        @LiteflowFact("user") User user,
+                        @LiteflowFact("user.company.address") String address) {
+        user.setName("jack");
+    }
+
+    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeType = NodeTypeEnum.COMMON, nodeId = "b")
+    public void processB(NodeComponent bindCmp,
+                        @LiteflowFact("user.company") Company company,
+                        @LiteflowFact("data2") Integer data) {
+        company.setHeadCount(20);
+    }
+
+    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeType = NodeTypeEnum.COMMON, nodeId = "c")
+    public void processC(NodeComponent bindCmp,
+                        @LiteflowFact("demo2Context.user") User user) {
+        user.setName("rose");
+    }
+
+    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeType = NodeTypeEnum.COMMON, nodeId = "d")
+    public void processD(NodeComponent bindCmp,
+                        @LiteflowFact("ctx.user") User user) {
+        user.setName("jelly");
+    }
+}

+ 40 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Company.java

@@ -0,0 +1,40 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+public class Company {
+
+    private String name;
+
+    private String address;
+
+    private int headCount;
+
+    public Company(String name, String address, int headCount) {
+        this.name = name;
+        this.address = address;
+        this.headCount = headCount;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public int getHeadCount() {
+        return headCount;
+    }
+
+    public void setHeadCount(int headCount) {
+        this.headCount = headCount;
+    }
+}

+ 24 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo1Context.java

@@ -0,0 +1,24 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+public class Demo1Context {
+
+    private String data1;
+
+    private Integer data2;
+
+    public String getData1() {
+        return data1;
+    }
+
+    public void setData1(String data1) {
+        this.data1 = data1;
+    }
+
+    public Integer getData2() {
+        return data2;
+    }
+
+    public void setData2(Integer data2) {
+        this.data2 = data2;
+    }
+}

+ 29 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo2Context.java

@@ -0,0 +1,29 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+public class Demo2Context {
+
+    private String data1;
+
+    private User user;
+
+    public Demo2Context(String data1, User user) {
+        this.data1 = data1;
+        this.user = user;
+    }
+
+    public String getData1() {
+        return data1;
+    }
+
+    public void setData1(String data1) {
+        this.data1 = data1;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+}

+ 32 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo3Context.java

@@ -0,0 +1,32 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+import com.yomahub.liteflow.context.ContextBean;
+
+@ContextBean("ctx")
+public class Demo3Context {
+
+    private String data1;
+
+    private User user;
+
+    public Demo3Context(String data1, User user) {
+        this.data1 = data1;
+        this.user = user;
+    }
+
+    public String getData1() {
+        return data1;
+    }
+
+    public void setData1(String data1) {
+        this.data1 = data1;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+}

+ 29 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/TestContext.java

@@ -0,0 +1,29 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+public class TestContext {
+
+    private User user;
+
+    private String data1;
+
+    public TestContext(User user, String data1) {
+        this.user = user;
+        this.data1 = data1;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    public String getData1() {
+        return data1;
+    }
+
+    public void setData1(String data1) {
+        this.data1 = data1;
+    }
+}

+ 53 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/User.java

@@ -0,0 +1,53 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+import java.util.Date;
+
+public class User {
+
+    private String name;
+
+    private int age;
+
+    private Date birthday;
+
+    private Company company;
+
+    public User(String name, int age, Date birthday, Company company) {
+        this.name = name;
+        this.age = age;
+        this.birthday = birthday;
+        this.company = company;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getAge() {
+        return age;
+    }
+
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    public Company getCompany() {
+        return company;
+    }
+
+    public void setCompany(Company company) {
+        this.company = company;
+    }
+
+    public Date getBirthday() {
+        return birthday;
+    }
+
+    public void setBirthday(Date birthday) {
+        this.birthday = birthday;
+    }
+}

+ 1 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/processFact/application.properties

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

+ 18 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/processFact/flow.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<flow>
+    <chain name="chain1">
+        THEN(a);
+    </chain>
+
+    <chain name="chain2">
+        THEN(b);
+    </chain>
+
+    <chain name="chain3">
+        THEN(c);
+    </chain>
+
+    <chain name="chain4">
+        THEN(d);
+    </chain>
+</flow>

+ 24 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathELDeclSpringbootTest.java

@@ -15,6 +15,7 @@ import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIf;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.slf4j.Logger;
@@ -65,6 +66,29 @@ public class AbsoluteConfigPathELDeclSpringbootTest extends BaseTest {
 		});
 	}
 
+	@Test
+	@EnabledIf("isWindows")
+	public void testAbsPath() throws Exception{
+		Assertions.assertTrue(() -> {
+			LiteflowConfig config = LiteflowConfigGetter.get();
+			config.setRuleSource(StrUtil.format("{}\\sub\\**\\*.xml",rootDir));
+			flowExecutor.reloadRule();
+			return flowExecutor.execute2Resp("chain1", "arg").isSuccess();
+		});
+	}
+
+	public static boolean isWindows() {
+		try {
+			String osName = System.getProperty("os.name");
+			if (osName.isEmpty()) return false;
+			else {
+				return osName.contains("Windows");
+			}
+		} catch (Exception e) {
+			return false;
+		}
+	}
+
 	@BeforeAll
 	public static void createFiles() {
 		rootDir = FileUtil.getAbsolutePath(ResourceUtil.getResource("").getPath());

+ 97 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/ProcessFactELDeclSpringbootTest.java

@@ -0,0 +1,97 @@
+package com.yomahub.liteflow.test.processFact;
+
+import cn.hutool.core.date.DateUtil;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import com.yomahub.liteflow.test.processFact.context.*;
+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;
+
+/**
+ * process方法上的fact映射参数测试
+ * @author Bryan.Zhang
+ */
+@ExtendWith(SpringExtension.class)
+@TestPropertySource(value = "classpath:/processFact/application.properties")
+@SpringBootTest(classes = ProcessFactELDeclSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.processFact.cmp"})
+public class ProcessFactELDeclSpringbootTest extends BaseTest {
+
+	@Resource
+	private FlowExecutor flowExecutor;
+
+	// 最基本的情况
+	@Test
+	public void testFact1() throws Exception {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", createContext());
+		Assertions.assertTrue(response.isSuccess());
+		TestContext context = response.getContextBean(TestContext.class);
+		Assertions.assertEquals("jack", context.getUser().getName());
+	}
+
+	// 多上下文自动搜寻
+	@Test
+	public void testFact2() throws Exception {
+		TestContext testContext = createContext();
+		Demo1Context demo1Context = new Demo1Context();
+		demo1Context.setData1("xxxx");
+		demo1Context.setData2(99);
+
+		LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg", demo1Context, testContext);
+		Assertions.assertTrue(response.isSuccess());
+		TestContext context = response.getContextBean(TestContext.class);
+		Assertions.assertEquals(20, context.getUser().getCompany().getHeadCount());
+	}
+
+	// 多上下文都有user,指定上下文中的user
+	@Test
+	public void testFact3() throws Exception {
+		TestContext testContext = createContext();
+		Demo2Context demo2Context = createDemo2Context();
+
+		LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg", testContext, demo2Context);
+		Assertions.assertTrue(response.isSuccess());
+		Demo2Context context = response.getContextBean(Demo2Context.class);
+		Assertions.assertEquals("rose", context.getUser().getName());
+	}
+
+	// 多上下文都有user,指定上下文中的user
+	@Test
+	public void testFact4() throws Exception {
+		Demo3Context demo3Context = createDemo3Context();
+
+		LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg", demo3Context);
+		Assertions.assertTrue(response.isSuccess());
+		Demo3Context context = response.getContextBean(Demo3Context.class);
+		Assertions.assertEquals("jelly", context.getUser().getName());
+	}
+
+	private TestContext createContext(){
+		Company company = new Company("XXX有限公司", "黄河路34号303室", 400);
+		User user = new User("张三", 18, DateUtil.parseDate("1990-08-20"), company);
+        return new TestContext(user, "this is data");
+	}
+
+	private Demo2Context createDemo2Context(){
+		Company company = new Company("XXX有限公司", "和平路12号101室", 600);
+		User user = new User("李四", 28, DateUtil.parseDate("1990-06-01"), company);
+		return new Demo2Context("xxx", user);
+	}
+
+	private Demo3Context createDemo3Context(){
+		Company company = new Company("XXX有限公司", "和平路12号101室", 600);
+		User user = new User("王五", 28, DateUtil.parseDate("1990-06-01"), company);
+		return new Demo3Context("xxx", user);
+	}
+
+}

+ 28 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/cmp/ACmp.java

@@ -0,0 +1,28 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.processFact.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowFact;
+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.test.processFact.context.User;
+import org.springframework.stereotype.Component;
+
+
+@Component("a")
+public class ACmp {
+
+	@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeType = NodeTypeEnum.COMMON)
+	public void process(NodeComponent bindCmp,
+						@LiteflowFact("user") User user,
+						@LiteflowFact("user.company.address") String address) {
+		user.setName("jack");
+	}
+}

+ 28 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/cmp/BCmp.java

@@ -0,0 +1,28 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.processFact.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowFact;
+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.test.processFact.context.Company;
+import org.springframework.stereotype.Component;
+
+@Component("b")
+public class BCmp {
+
+	@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeType = NodeTypeEnum.COMMON)
+	public void process(NodeComponent bindCmp,
+						@LiteflowFact("user.company") Company company,
+						@LiteflowFact("data2") Integer data) {
+		company.setHeadCount(20);
+	}
+
+}

+ 27 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/cmp/CCmp.java

@@ -0,0 +1,27 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.processFact.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowFact;
+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.test.processFact.context.User;
+import org.springframework.stereotype.Component;
+
+@Component("c")
+public class CCmp {
+
+	@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeType = NodeTypeEnum.COMMON)
+	public void process(NodeComponent bindCmp,
+						@LiteflowFact("demo2Context.user") User user) {
+		user.setName("rose");
+	}
+
+}

+ 27 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/cmp/DCmp.java

@@ -0,0 +1,27 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.processFact.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowFact;
+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.test.processFact.context.User;
+import org.springframework.stereotype.Component;
+
+@Component("d")
+public class DCmp {
+
+	@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeType = NodeTypeEnum.COMMON)
+	public void process(NodeComponent bindCmp,
+						@LiteflowFact("ctx.user") User user) {
+		user.setName("jelly");
+	}
+
+}

+ 40 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Company.java

@@ -0,0 +1,40 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+public class Company {
+
+    private String name;
+
+    private String address;
+
+    private int headCount;
+
+    public Company(String name, String address, int headCount) {
+        this.name = name;
+        this.address = address;
+        this.headCount = headCount;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public int getHeadCount() {
+        return headCount;
+    }
+
+    public void setHeadCount(int headCount) {
+        this.headCount = headCount;
+    }
+}

+ 24 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo1Context.java

@@ -0,0 +1,24 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+public class Demo1Context {
+
+    private String data1;
+
+    private Integer data2;
+
+    public String getData1() {
+        return data1;
+    }
+
+    public void setData1(String data1) {
+        this.data1 = data1;
+    }
+
+    public Integer getData2() {
+        return data2;
+    }
+
+    public void setData2(Integer data2) {
+        this.data2 = data2;
+    }
+}

+ 29 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo2Context.java

@@ -0,0 +1,29 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+public class Demo2Context {
+
+    private String data1;
+
+    private User user;
+
+    public Demo2Context(String data1, User user) {
+        this.data1 = data1;
+        this.user = user;
+    }
+
+    public String getData1() {
+        return data1;
+    }
+
+    public void setData1(String data1) {
+        this.data1 = data1;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+}

+ 32 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/Demo3Context.java

@@ -0,0 +1,32 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+import com.yomahub.liteflow.context.ContextBean;
+
+@ContextBean("ctx")
+public class Demo3Context {
+
+    private String data1;
+
+    private User user;
+
+    public Demo3Context(String data1, User user) {
+        this.data1 = data1;
+        this.user = user;
+    }
+
+    public String getData1() {
+        return data1;
+    }
+
+    public void setData1(String data1) {
+        this.data1 = data1;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+}

+ 29 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/TestContext.java

@@ -0,0 +1,29 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+public class TestContext {
+
+    private User user;
+
+    private String data1;
+
+    public TestContext(User user, String data1) {
+        this.user = user;
+        this.data1 = data1;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    public String getData1() {
+        return data1;
+    }
+
+    public void setData1(String data1) {
+        this.data1 = data1;
+    }
+}

+ 53 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/processFact/context/User.java

@@ -0,0 +1,53 @@
+package com.yomahub.liteflow.test.processFact.context;
+
+import java.util.Date;
+
+public class User {
+
+    private String name;
+
+    private int age;
+
+    private Date birthday;
+
+    private Company company;
+
+    public User(String name, int age, Date birthday, Company company) {
+        this.name = name;
+        this.age = age;
+        this.birthday = birthday;
+        this.company = company;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getAge() {
+        return age;
+    }
+
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    public Company getCompany() {
+        return company;
+    }
+
+    public void setCompany(Company company) {
+        this.company = company;
+    }
+
+    public Date getBirthday() {
+        return birthday;
+    }
+
+    public void setBirthday(Date birthday) {
+        this.birthday = birthday;
+    }
+}

+ 1 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/processFact/application.properties

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

+ 18 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/processFact/flow.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<flow>
+    <chain name="chain1">
+        THEN(a);
+    </chain>
+
+    <chain name="chain2">
+        THEN(b);
+    </chain>
+
+    <chain name="chain3">
+        THEN(c);
+    </chain>
+
+    <chain name="chain4">
+        THEN(d);
+    </chain>
+</flow>

+ 24 - 0
liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathTest.java

@@ -14,6 +14,7 @@ import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIf;
 
 import java.util.Objects;
 
@@ -50,6 +51,29 @@ public class AbsoluteConfigPathTest extends BaseTest {
 		});
 	}
 
+	@Test
+	@EnabledIf("isWindows")
+	public void testAbsPath() throws Exception{
+		Assertions.assertTrue(() -> {
+			LiteflowConfig config = new LiteflowConfig();
+			config.setRuleSource(StrUtil.format("{}\\sub\\**\\*.xml",rootDir));
+			flowExecutor = FlowExecutorHolder.loadInstance(config);
+			return flowExecutor.execute2Resp("chain1", "arg").isSuccess();
+		});
+	}
+
+	public static boolean isWindows() {
+		try {
+			String osName = System.getProperty("os.name");
+			if (osName.isEmpty()) return false;
+			else {
+				return osName.contains("Windows");
+			}
+		} catch (Exception e) {
+			return false;
+		}
+	}
+
 	@BeforeAll
 	public static void createFiles() {
 		rootDir = FileUtil.getAbsolutePath(ResourceUtil.getResource("").getPath());

+ 66 - 0
liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/java/com/yomahub/liteflow/test/namespace/RouteSpringbootNamespaceTest.java

@@ -0,0 +1,66 @@
+package com.yomahub.liteflow.test.namespace;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.exception.NoMatchedRouteChainException;
+import com.yomahub.liteflow.exception.RouteChainNotFoundException;
+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.function.Executable;
+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 javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * springboot环境EL常规的例子测试
+ *
+ * @author Bryan.Zhang
+ */
+@TestPropertySource(value = "classpath:/namespace/application.properties")
+@SpringBootTest(classes = RouteSpringbootNamespaceTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.namespace.cmp" })
+public class RouteSpringbootNamespaceTest extends BaseTest {
+
+	@Resource
+	private FlowExecutor flowExecutor;
+
+	// n1 space中的两个链路都能匹配
+	@Test
+	public void testNamespaceRoute1() throws Exception {
+		List<LiteflowResponse> responseList = flowExecutor.executeRouteChain("n1", 15, DefaultContext.class);
+		LiteflowResponse response1 = responseList.stream().filter(
+				liteflowResponse -> liteflowResponse.getChainId().equals("r_chain1")
+		).findFirst().orElse(null);
+
+		assert response1 != null;
+		Assertions.assertTrue(response1.isSuccess());
+		Assertions.assertEquals("b==>a", response1.getExecuteStepStr());
+
+		LiteflowResponse response2 = responseList.stream().filter(
+				liteflowResponse -> liteflowResponse.getChainId().equals("r_chain2")
+		).findFirst().orElse(null);
+
+		assert response2 != null;
+		Assertions.assertTrue(response2.isSuccess());
+		Assertions.assertEquals("a==>b", response2.getExecuteStepStr());
+	}
+
+	// n1这个namespace中没有规则被匹配上
+	@Test
+	public void testNamespaceRoute2() throws Exception {
+		Assertions.assertThrows(NoMatchedRouteChainException.class, () -> flowExecutor.executeRouteChain("n1", 8, DefaultContext.class));
+	}
+
+	// 没有n3这个namespace
+	@Test
+	public void testNamespaceRoute3() throws Exception {
+		Assertions.assertThrows(RouteChainNotFoundException.class, () -> flowExecutor.executeRouteChain("n3", 8, DefaultContext.class));
+	}
+}

+ 20 - 0
liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/java/com/yomahub/liteflow/test/namespace/cmp/ACmp.java

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

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/java/com/yomahub/liteflow/test/namespace/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.namespace.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("b")
+public class BCmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("BCmp executed!");
+	}
+
+}

+ 13 - 0
liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/java/com/yomahub/liteflow/test/namespace/cmp/R1.java

@@ -0,0 +1,13 @@
+package com.yomahub.liteflow.test.namespace.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeBooleanComponent;
+
+@LiteflowComponent("r1")
+public class R1 extends NodeBooleanComponent {
+    @Override
+    public boolean processBoolean() throws Exception {
+        int testInt = this.getRequestData();
+        return testInt >= 10 && testInt <= 20;
+    }
+}

+ 13 - 0
liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/java/com/yomahub/liteflow/test/namespace/cmp/R2.java

@@ -0,0 +1,13 @@
+package com.yomahub.liteflow.test.namespace.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeBooleanComponent;
+
+@LiteflowComponent("r2")
+public class R2 extends NodeBooleanComponent {
+    @Override
+    public boolean processBoolean() throws Exception {
+        int testInt = this.getRequestData();
+        return testInt > 100;
+    }
+}

+ 1 - 0
liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/resources/namespace/application.properties

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

+ 30 - 0
liteflow-testcase-el/liteflow-testcase-el-routechain/src/test/resources/namespace/flow.el.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE flow PUBLIC  "liteflow" "liteflow.dtd">
+<flow>
+    <chain name="r_chain1" namespace="n1">
+        <route>
+            r1
+        </route>
+        <body>
+            THEN(b,a);
+        </body>
+    </chain>
+
+    <chain name="r_chain2" namespace="n1">
+        <route>
+            OR(r1,r2)
+        </route>
+        <body>
+            THEN(a,b);
+        </body>
+    </chain>
+
+    <chain name="r_chain3" namespace="n2">
+        <route>
+            r2
+        </route>
+        <body>
+            THEN(b,b);
+        </body>
+    </chain>
+</flow>

+ 32 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/pom.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>liteflow-testcase-el</artifactId>
+        <groupId>com.yomahub</groupId>
+        <version>${revision}</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>liteflow-testcase-el-script-kotlin-springboot</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.yomahub</groupId>
+            <artifactId>liteflow-spring-boot-starter</artifactId>
+            <version>${revision}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.yomahub</groupId>
+            <artifactId>liteflow-script-kotlin</artifactId>
+            <version>${revision}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 24 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/BaseTest.java

@@ -0,0 +1,24 @@
+package com.yomahub.liteflow.test.script;
+
+import com.yomahub.liteflow.core.FlowInitHook;
+import com.yomahub.liteflow.flow.FlowBus;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.spi.holder.SpiFactoryCleaner;
+import com.yomahub.liteflow.spring.ComponentScanner;
+import com.yomahub.liteflow.thread.ExecutorHelper;
+import org.junit.jupiter.api.AfterAll;
+
+public class BaseTest {
+
+	@AfterAll
+	public static void cleanScanCache() {
+		ComponentScanner.cleanCache();
+		FlowBus.cleanCache();
+		ExecutorHelper.loadInstance().clearExecutorServiceMap();
+		SpiFactoryCleaner.clean();
+		LiteflowConfigGetter.clean();
+		FlowInitHook.cleanHook();
+		FlowBus.clearStat();
+	}
+
+}

+ 36 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/cmpdata/LiteFlowCmpDataKotlinScriptELTest.java

@@ -0,0 +1,36 @@
+package com.yomahub.liteflow.test.script.kotlin.cmpdata;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.slot.DefaultContext;
+import com.yomahub.liteflow.test.script.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:/cmpdata/application.properties")
+@SpringBootTest(classes = LiteFlowCmpDataKotlinScriptELTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.script.kotlin.cmpdata.cmp" })
+public class LiteFlowCmpDataKotlinScriptELTest extends BaseTest {
+
+	@Resource
+	private FlowExecutor flowExecutor;
+
+	@Test
+	public void testCmpData1() throws Exception {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+		DefaultContext context = response.getFirstContextBean();
+		Assertions.assertTrue(response.isSuccess());
+		Assertions.assertEquals("1995-10-01", context.getData("s1"));
+	}
+
+}

+ 22 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/cmpdata/cmp/ACmp.java

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

+ 91 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/common/LiteFlowKotlinScriptCommonELTest.java

@@ -0,0 +1,91 @@
+package com.yomahub.liteflow.test.script.kotlin.common;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.slot.DefaultContext;
+import com.yomahub.liteflow.test.script.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;
+
+/**
+ * Kotlin 脚本测试
+ *
+ * @author DaleLee
+ */
+
+@ExtendWith(SpringExtension.class)
+@TestPropertySource(value = "classpath:/common/application.properties")
+@SpringBootTest(classes = LiteFlowKotlinScriptCommonELTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.script.kotlin.common.cmp"})
+public class LiteFlowKotlinScriptCommonELTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testCommonScript1() {
+        LiteflowResponse response = flowExecutor.execute2Resp("testCommonScript1", "arg");
+        Assertions.assertTrue(response.isSuccess());
+        DefaultContext context = response.getFirstContextBean();
+        Assertions.assertEquals(Integer.valueOf(5), context.getData("s1"));
+    }
+
+    @Test
+    public void testForScript1() {
+        DefaultContext context = new DefaultContext();
+        context.setData("k1", 1);
+        context.setData("k2", 2);
+        LiteflowResponse response = flowExecutor.execute2Resp("testForScript1", "arg", context);
+        Assertions.assertTrue(response.isSuccess());
+        Assertions.assertEquals("s2==>a==>a==>a", response.getExecuteStepStr());
+    }
+
+    @Test
+    public void testBooleanScript1() {
+        LiteflowResponse response = flowExecutor.execute2Resp("testBooleanScript1", "arg");
+        Assertions.assertTrue(response.isSuccess());
+        Assertions.assertEquals("s3==>b", response.getExecuteStepStr());
+    }
+
+    @Test
+    public void testBooleanScript2() {
+        LiteflowResponse response = flowExecutor.execute2Resp("testBooleanScript2", "arg");
+        Assertions.assertTrue(response.isSuccess());
+        Assertions.assertEquals("s4", response.getExecuteStepStr());
+    }
+
+    @Test
+    public void testBooleanScript3() {
+        DefaultContext context = new DefaultContext();
+        context.setData("count", 2);
+        LiteflowResponse response = flowExecutor.execute2Resp("testBooleanScript3", "arg", context);
+        Assertions.assertTrue(response.isSuccess());
+        Assertions.assertEquals("s3==>b==>s6==>s3==>b==>s6==>s3==>b==>s6",response.getExecuteStepStr());
+    }
+
+    @Test
+    public void testSwitchScript1() {
+        DefaultContext context = new DefaultContext();
+        context.setData("id", "c");
+        LiteflowResponse response = flowExecutor.execute2Resp("testSwitchScript1", "arg", context);
+        Assertions.assertTrue(response.isSuccess());
+        Assertions.assertEquals("s5==>c", response.getExecuteStepStr());
+    }
+
+    @Test
+    public void testFileScript1() {
+        LiteflowResponse response = flowExecutor.execute2Resp("testFileScript1", "arg");
+        Assertions.assertTrue(response.isSuccess());
+        DefaultContext context = response.getFirstContextBean();
+        Assertions.assertEquals(Integer.valueOf(6), context.getData("s7"));
+    }
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/common/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.kotlin.common.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-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/common/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.kotlin.common.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!");
+	}
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/common/cmp/CCmp.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.kotlin.common.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeComponent;
+
+@LiteflowComponent("c")
+public class CCmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 57 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/LiteFlowScriptContextbeanKotlinELTest.java

@@ -0,0 +1,57 @@
+package com.yomahub.liteflow.test.script.kotlin.contextbean;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.test.script.BaseTest;
+import com.yomahub.liteflow.test.script.kotlin.contextbean.bean.CheckContext;
+import com.yomahub.liteflow.test.script.kotlin.contextbean.bean.Order2Context;
+import com.yomahub.liteflow.test.script.kotlin.contextbean.bean.OrderContext;
+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:/contextbean/application.properties")
+@SpringBootTest(classes = LiteFlowScriptContextbeanKotlinELTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.script.kotlin.contextbean.cmp",
+		"com.yomahub.liteflow.test.script.kotlin.contextbean.bean" })
+public class LiteFlowScriptContextbeanKotlinELTest extends BaseTest {
+
+	@Resource
+	private FlowExecutor flowExecutor;
+
+	@Test
+	public void testContextBean1() {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", OrderContext.class, CheckContext.class,
+				Order2Context.class);
+		Assertions.assertTrue(response.isSuccess());
+		OrderContext orderContext = response.getContextBean(OrderContext.class);
+		CheckContext checkContext = response.getContextBean(CheckContext.class);
+		Order2Context order2Context = response.getContextBean(Order2Context.class);
+		Assertions.assertEquals("order1", orderContext.getOrderNo());
+		Assertions.assertEquals("sign1", checkContext.getSign());
+		Assertions.assertEquals("order2", order2Context.getOrderNo());
+	}
+
+	@Test
+	public void testContextBean2() throws Exception {
+		OrderContext orderContext = new OrderContext();
+		orderContext.setOrderNo("order1");
+		CheckContext checkContext = new CheckContext();
+		checkContext.setSign("sign1");
+		Order2Context orderContext2 = new Order2Context();
+		orderContext2.setOrderNo("order2");
+		LiteflowResponse response = flowExecutor.execute2Resp("chain2", null, orderContext, checkContext,
+				orderContext2);
+		Assertions.assertTrue(response.isSuccess());
+	}
+
+}

+ 28 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/bean/CheckContext.java

@@ -0,0 +1,28 @@
+package com.yomahub.liteflow.test.script.kotlin.contextbean.bean;
+
+import com.yomahub.liteflow.context.ContextBean;
+
+@ContextBean
+public class CheckContext {
+
+	private String sign;
+
+	private int randomId;
+
+	public String getSign() {
+		return sign;
+	}
+
+	public void setSign(String sign) {
+		this.sign = sign;
+	}
+
+	public int getRandomId() {
+		return randomId;
+	}
+
+	public void setRandomId(int randomId) {
+		this.randomId = randomId;
+	}
+
+}

+ 37 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/bean/Order2Context.java

@@ -0,0 +1,37 @@
+package com.yomahub.liteflow.test.script.kotlin.contextbean.bean;
+
+import java.util.Date;
+
+public class Order2Context {
+
+	private String orderNo;
+
+	private int orderType;
+
+	private Date createTime;
+
+	public String getOrderNo() {
+		return orderNo;
+	}
+
+	public void setOrderNo(String orderNo) {
+		this.orderNo = orderNo;
+	}
+
+	public int getOrderType() {
+		return orderType;
+	}
+
+	public void setOrderType(int orderType) {
+		this.orderType = orderType;
+	}
+
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+}

+ 40 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/bean/OrderContext.java

@@ -0,0 +1,40 @@
+package com.yomahub.liteflow.test.script.kotlin.contextbean.bean;
+
+import com.yomahub.liteflow.context.ContextBean;
+
+import java.util.Date;
+
+@ContextBean("order")
+public class OrderContext {
+
+	private String orderNo;
+
+	private int orderType;
+
+	private Date createTime;
+
+	public String getOrderNo() {
+		return orderNo;
+	}
+
+	public void setOrderNo(String orderNo) {
+		this.orderNo = orderNo;
+	}
+
+	public int getOrderType() {
+		return orderType;
+	}
+
+	public void setOrderType(int orderType) {
+		this.orderType = orderType;
+	}
+
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/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.kotlin.contextbean.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("a")
+public class ACmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("ACmp executed!");
+	}
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/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.kotlin.contextbean.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("b")
+public class BCmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("BCmp executed!");
+	}
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/contextbean/cmp/CCmp.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.kotlin.contextbean.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("c")
+public class CCmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 37 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/meta/LiteflowKotlinScriptMetaELTest.java

@@ -0,0 +1,37 @@
+package com.yomahub.liteflow.test.script.kotlin.meta;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.slot.DefaultContext;
+import com.yomahub.liteflow.test.script.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:/meta/application.properties")
+@SpringBootTest(classes = LiteflowKotlinScriptMetaELTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.script.kotlin.meta.cmp"})
+public class LiteflowKotlinScriptMetaELTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testMeta() {
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+        DefaultContext context = response.getFirstContextBean();
+        Assertions.assertTrue(response.isSuccess());
+        Assertions.assertEquals("chain1", context.getData("currChainId"));
+        Assertions.assertEquals("arg", context.getData("requestData"));
+        Assertions.assertEquals("s1", context.getData("nodeId"));
+    }
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/meta/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.kotlin.meta.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-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/meta/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.kotlin.meta.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!");
+	}
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/meta/cmp/CCmp.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.kotlin.meta.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeComponent;
+
+@LiteflowComponent("c")
+public class CCmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 48 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/refresh/LiteflowKotlinScriptRefreshELTest.java

@@ -0,0 +1,48 @@
+package com.yomahub.liteflow.test.script.kotlin.refresh;
+
+import cn.hutool.core.io.resource.ResourceUtil;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.enums.FlowParserTypeEnum;
+import com.yomahub.liteflow.flow.FlowBus;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.test.script.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 = LiteflowKotlinScriptRefreshELTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.script.kotlin.refresh.cmp" })
+public class LiteflowKotlinScriptRefreshELTest extends BaseTest {
+
+	@Resource
+	private FlowExecutor flowExecutor;
+
+	// 测试脚本的热重载
+	@Test
+	public void testRefresh1() throws Exception {
+		// 根据配置,加载的应该是flow.xml,执行原来的规则
+		LiteflowResponse responseOld = flowExecutor.execute2Resp("chain1", "arg");
+		Assertions.assertTrue(responseOld.isSuccess());
+		Assertions.assertEquals("d==>s1[选择脚本]==>a", responseOld.getExecuteStepStr());
+		// 更改规则,重新加载,更改的规则内容从flow_update.xml里读取,这里只是为了模拟下获取新的内容。不一定是从文件中读取
+		String newContent = ResourceUtil.readUtf8Str("classpath: /refresh/flow_update.xml");
+		// 进行刷新
+		FlowBus.refreshFlowMetaData(FlowParserTypeEnum.TYPE_EL_XML, newContent);
+
+		// 重新执行chain2这个链路,结果会变
+		LiteflowResponse responseNew = flowExecutor.execute2Resp("chain1", "arg");
+		Assertions.assertTrue(responseNew.isSuccess());
+		Assertions.assertEquals("d==>s1[选择脚本_改]==>b==>s2[普通脚本_新增]", responseNew.getExecuteStepStr());
+	}
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/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.kotlin.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-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/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.kotlin.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!");
+	}
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/refresh/cmp/CCmp.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.kotlin.refresh.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeComponent;
+
+@LiteflowComponent("c")
+public class CCmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 24 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/refresh/cmp/DCmp.java

@@ -0,0 +1,24 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.script.kotlin.refresh.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.slot.DefaultContext;
+
+@LiteflowComponent("d")
+public class DCmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		DefaultContext context = this.getFirstContextBean();
+		context.setData("count", 198);
+		System.out.println("DCmp executed!");
+	}
+
+}

+ 114 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/remove/LiteFlowKotlinScriptRemoveELTest.java

@@ -0,0 +1,114 @@
+package com.yomahub.liteflow.test.script.kotlin.remove;
+
+import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
+import com.yomahub.liteflow.exception.ELParseException;
+import com.yomahub.liteflow.flow.FlowBus;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.script.ScriptExecutor;
+import com.yomahub.liteflow.script.ScriptExecutorFactory;
+import com.yomahub.liteflow.script.exception.ScriptLoadException;
+import com.yomahub.liteflow.slot.DefaultContext;
+import com.yomahub.liteflow.test.script.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.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 测试脚本的卸载和重载功能
+ *
+ * @author DaleLee
+ */
+@ExtendWith(SpringExtension.class)
+@TestPropertySource(value = "classpath:/remove/application.properties")
+@SpringBootTest(classes = LiteFlowKotlinScriptRemoveELTest.class)
+@EnableAutoConfiguration
+public class LiteFlowKotlinScriptRemoveELTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    private ScriptExecutor scriptExecutor = ScriptExecutorFactory.loadInstance()
+            .getScriptExecutor(ScriptTypeEnum.KOTLIN.getDisplayName());
+
+    // 仅卸载脚本
+    @Test
+    public void testUnload() {
+        flowExecutor.reloadRule();
+
+        // 获取节点id
+        List<String> nodeIds = scriptExecutor.getNodeIds();
+        Assertions.assertEquals(2, nodeIds.size());
+        Assertions.assertTrue(nodeIds.contains("s1"));
+        Assertions.assertTrue(nodeIds.contains("s2"));
+
+        // 保证脚本可以正常运行
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+        Assertions.assertTrue(response.isSuccess());
+        DefaultContext context = response.getFirstContextBean();
+        Assertions.assertEquals(Integer.valueOf(6), context.getData("s1"));
+
+        // 卸载脚本
+        scriptExecutor.unLoad("s1");
+        response = flowExecutor.execute2Resp("chain1", "arg");
+        Assertions.assertFalse(response.isSuccess());
+        Assertions.assertEquals(ScriptLoadException.class, response.getCause().getClass());
+        Assertions.assertEquals("script for node[s1] is not loaded", response.getMessage());
+
+        // 脚本已卸载
+        Assertions.assertFalse(scriptExecutor.getNodeIds().contains("s1"));
+    }
+
+    // 卸载节点和脚本
+    @Test
+    public void testRemove() {
+        flowExecutor.reloadRule();
+
+        // 保证脚本可以正常运行
+        LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
+        Assertions.assertTrue(response.isSuccess());
+        DefaultContext context = response.getFirstContextBean();
+        Assertions.assertEquals(Integer.valueOf(5), context.getData("s2"));
+
+        // 卸载节点
+        FlowBus.unloadScriptNode("s2");
+
+        // 旧 chain 报脚本加载错误
+        response = flowExecutor.execute2Resp("chain2", "arg");
+        Assertions.assertEquals(ScriptLoadException.class, response.getCause().getClass());
+
+        // 新 chian 会找不到节点
+        Assertions.assertThrows(ELParseException.class,
+                () -> LiteFlowChainELBuilder.createChain()
+                        .setChainId("chain3")
+                        .setEL("THEN(s2)")
+                        .build());
+
+        // 节点已卸载
+        Assertions.assertFalse(FlowBus.containNode("s2"));
+        // 脚本已卸载
+        Assertions.assertFalse(scriptExecutor.getNodeIds().contains("s2"));
+    }
+
+    // 重载脚本
+    @Test
+    public void testReloadScript() {
+        flowExecutor.reloadRule();
+        String script = "(bindings[\"defaultContext\"] as? DefaultContext)?.setData(\"s1\", \"abc\")";
+        FlowBus.reloadScript("s1", script);
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+        DefaultContext context = response.getFirstContextBean();
+        // 执行结果变更
+        Assertions.assertEquals("abc", context.getData("s1"));
+        // 脚本变更
+        Assertions.assertEquals(FlowBus.getNode("s1").getScript(), script);
+    }
+}

+ 103 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/LiteFlowScriptScriptbeanKotlinELTest.java

@@ -0,0 +1,103 @@
+package com.yomahub.liteflow.test.script.kotlin.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.script.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;
+import java.util.HashMap;
+import java.util.Map;
+
+@ExtendWith(SpringExtension.class)
+@TestPropertySource(value = "classpath:/scriptbean/application.properties")
+@SpringBootTest(classes = LiteFlowScriptScriptbeanKotlinELTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.script.kotlin.scriptbean.cmp",
+		"com.yomahub.liteflow.test.script.kotlin.scriptbean.bean" })
+public class LiteFlowScriptScriptbeanKotlinELTest extends BaseTest {
+
+	@Resource
+	private FlowExecutor flowExecutor;
+
+	@Test
+	public void testScriptBean1() throws Exception {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+		Assertions.assertTrue(response.isSuccess());
+		DefaultContext context = response.getFirstContextBean();
+		Assertions.assertEquals("hello", context.getData("demo"));
+	}
+
+	@Test
+	public void testScriptBean2() throws Exception {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
+		Assertions.assertTrue(response.isSuccess());
+		DefaultContext context = response.getFirstContextBean();
+		Assertions.assertEquals("hello,kobe", context.getData("demo"));
+	}
+
+	// 测试scriptBean includeMethodName配置包含情况下
+	@Test
+	public void testScriptBean3() throws Exception {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
+		Assertions.assertTrue(response.isSuccess());
+		DefaultContext context = response.getFirstContextBean();
+		Assertions.assertEquals("hello,kobe", context.getData("demo"));
+	}
+
+	// 测试scriptBean includeMethodName配置不包含情况下
+	@Test
+	public void testScriptBean4() throws Exception {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
+		Assertions.assertFalse(response.isSuccess());
+		Assertions.assertEquals(ScriptBeanMethodInvokeException.class, response.getCause().getClass());
+	}
+
+	// 测试scriptBean excludeMethodName配置不包含情况下
+	@Test
+	public void testScriptBean5() throws Exception {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
+		Assertions.assertTrue(response.isSuccess());
+		DefaultContext context = response.getFirstContextBean();
+		Assertions.assertEquals("hello,kobe", context.getData("demo"));
+	}
+
+	// 测试scriptBean excludeMethodName配置包含情况下
+	@Test
+	public void testScriptBean6() throws Exception {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
+		Assertions.assertFalse(response.isSuccess());
+		Assertions.assertEquals(ScriptBeanMethodInvokeException.class, response.getCause().getClass());
+	}
+
+	// 测试在ScriptBeanManager里放入上下文,实现自定义脚本引用名称
+	@Test
+	public void testScriptBean7() throws Exception {
+		Map<String, String> map = new HashMap<>();
+		ScriptBeanManager.addScriptBean("abcCx", map);
+		LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg", map);
+		Assertions.assertTrue(response.isSuccess());
+		Map<String, String> context = response.getFirstContextBean();
+		Assertions.assertEquals("hello", context.get("demo"));
+	}
+
+	//测试用构造方法的方式注入bean的场景
+	@Test
+	public void testScriptBean8() throws Exception {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain8", "arg");
+		Assertions.assertTrue(response.isSuccess());
+		DefaultContext context = response.getFirstContextBean();
+		Assertions.assertEquals("hello,jordan", context.getData("demo"));
+	}
+
+}

+ 23 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/bean/DemoBean1.java

@@ -0,0 +1,23 @@
+package com.yomahub.liteflow.test.script.kotlin.scriptbean.bean;
+
+import com.yomahub.liteflow.script.annotation.ScriptBean;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+@Component
+@ScriptBean("demo")
+public class DemoBean1 {
+
+	@Resource
+	private DemoBean2 demoBean2;
+
+	public String getDemoStr1() {
+		return "hello";
+	}
+
+	public String getDemoStr2(String name) {
+		return demoBean2.getDemoStr2(name);
+	}
+
+}

+ 12 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/bean/DemoBean2.java

@@ -0,0 +1,12 @@
+package com.yomahub.liteflow.test.script.kotlin.scriptbean.bean;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class DemoBean2 {
+
+	public String getDemoStr2(String name) {
+		return "hello," + name;
+	}
+
+}

+ 22 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/bean/DemoBean3.java

@@ -0,0 +1,22 @@
+package com.yomahub.liteflow.test.script.kotlin.scriptbean.bean;
+
+import com.yomahub.liteflow.script.annotation.ScriptBean;
+import org.springframework.stereotype.Component;
+
+@Component
+@ScriptBean(name = "demo3", includeMethodName = { "test1", "test2" })
+public class DemoBean3 {
+
+	public String test1(String name) {
+		return "hello," + name;
+	}
+
+	public String test2(String name) {
+		return "hello," + name;
+	}
+
+	public String test3(String name) {
+		return "hello," + name;
+	}
+
+}

+ 22 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/bean/DemoBean4.java

@@ -0,0 +1,22 @@
+package com.yomahub.liteflow.test.script.kotlin.scriptbean.bean;
+
+import com.yomahub.liteflow.script.annotation.ScriptBean;
+import org.springframework.stereotype.Component;
+
+@Component
+@ScriptBean(name = "demo4", excludeMethodName = { "test2", "test3" })
+public class DemoBean4 {
+
+	public String test1(String name) {
+		return "hello," + name;
+	}
+
+	public String test2(String name) {
+		return "hello," + name;
+	}
+
+	public String test3(String name) {
+		return "hello," + name;
+	}
+
+}

+ 24 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/bean/DemoBean5.java

@@ -0,0 +1,24 @@
+package com.yomahub.liteflow.test.script.kotlin.scriptbean.bean;
+
+import com.yomahub.liteflow.script.annotation.ScriptBean;
+import org.springframework.stereotype.Component;
+
+@Component
+@ScriptBean("demo5")
+public class DemoBean5 {
+
+	private final DemoBean2 demoBean2;
+
+	public DemoBean5(DemoBean2 demoBean2) {
+		this.demoBean2 = demoBean2;
+	}
+
+	public String getDemoStr1() {
+		return "hello";
+	}
+
+	public String getDemoStr2(String name) {
+		return demoBean2.getDemoStr2(name);
+	}
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/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.kotlin.scriptbean.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("a")
+public class ACmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("ACmp executed!");
+	}
+
+}

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-kotlin-springboot/src/test/java/com/yomahub/liteflow/test/script/kotlin/scriptbean/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.kotlin.scriptbean.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("b")
+public class BCmp extends NodeComponent {
+
+	@Override
+	public void process() {
+		System.out.println("BCmp executed!");
+	}
+
+}

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů