Parcourir la source

Merge branch 'dev'

everywhere.z il y a 2 ans
Parent
commit
26c24692cf
100 fichiers modifiés avec 2096 ajouts et 482 suppressions
  1. 2 2
      README.zh-CN.md
  2. 4 0
      liteflow-core/pom.xml
  3. 11 1
      liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java
  4. 6 5
      liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java
  5. 26 0
      liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/CatchOperator.java
  6. 26 13
      liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/DoOperator.java
  7. 1 1
      liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ElifOperator.java
  8. 1 1
      liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IfOperator.java
  9. 14 0
      liteflow-core/src/main/java/com/yomahub/liteflow/builder/prop/NodePropBean.java
  10. 4 0
      liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java
  11. 25 0
      liteflow-core/src/main/java/com/yomahub/liteflow/context/ContextBean.java
  12. 53 24
      liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java
  13. 3 3
      liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptBreakComponent.java
  14. 3 3
      liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptCommonComponent.java
  15. 1 1
      liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptComponent.java
  16. 3 3
      liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptForComponent.java
  17. 3 3
      liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptIfComponent.java
  18. 3 3
      liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptSwitchComponent.java
  19. 3 3
      liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptWhileComponent.java
  20. 3 1
      liteflow-core/src/main/java/com/yomahub/liteflow/enums/ConditionTypeEnum.java
  21. 44 0
      liteflow-core/src/main/java/com/yomahub/liteflow/enums/ScriptTypeEnum.java
  22. 29 0
      liteflow-core/src/main/java/com/yomahub/liteflow/exception/CatchErrorException.java
  23. 28 0
      liteflow-core/src/main/java/com/yomahub/liteflow/exception/MonitorFileInitErrorException.java
  24. 8 10
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java
  25. 1 3
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/LiteflowResponse.java
  26. 10 0
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java
  27. 61 0
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/CatchCondition.java
  28. 67 5
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/Condition.java
  29. 34 0
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ConditionKey.java
  30. 1 1
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/FinallyCondition.java
  31. 14 7
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java
  32. 19 11
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IfCondition.java
  33. 15 7
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java
  34. 18 18
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java
  35. 1 1
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/PreCondition.java
  36. 23 20
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/SwitchCondition.java
  37. 23 15
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ThenCondition.java
  38. 1 1
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java
  39. 15 7
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java
  40. 4 0
      liteflow-core/src/main/java/com/yomahub/liteflow/monitor/MonitorBus.java
  41. 94 0
      liteflow-core/src/main/java/com/yomahub/liteflow/monitor/MonitorFile.java
  42. 1 0
      liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalJsonFlowELParser.java
  43. 6 2
      liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java
  44. 11 0
      liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java
  45. 4 0
      liteflow-core/src/main/java/com/yomahub/liteflow/script/ScriptExecutor.java
  46. 43 9
      liteflow-core/src/main/java/com/yomahub/liteflow/script/ScriptExecutorFactory.java
  47. 11 4
      liteflow-core/src/main/java/com/yomahub/liteflow/script/jsr223/JSR223ScriptExecutor.java
  48. 4 0
      liteflow-core/src/main/java/com/yomahub/liteflow/slot/Slot.java
  49. 17 1
      liteflow-core/src/main/java/com/yomahub/liteflow/spi/PathContentParser.java
  50. 34 4
      liteflow-core/src/main/java/com/yomahub/liteflow/spi/local/LocalPathContentParser.java
  51. 4 1
      liteflow-core/src/main/java/com/yomahub/liteflow/util/LOGOPrinter.java
  52. 248 246
      liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/util/JDBCHelper.java
  53. 15 1
      liteflow-script-plugin/liteflow-script-graaljs/src/main/java/com/yomahub/liteflow/script/graaljs/GraalJavaScriptExecutor.java
  54. 3 2
      liteflow-script-plugin/liteflow-script-groovy/src/main/java/com/yomahub/liteflow/script/groovy/GroovyScriptExecutor.java
  55. 5 4
      liteflow-script-plugin/liteflow-script-javascript/src/main/java/com/yomahub/liteflow/script/javascript/JavaScriptExecutor.java
  56. 3 2
      liteflow-script-plugin/liteflow-script-lua/src/main/java/com/yomahub/liteflow/script/lua/LuaScriptExecutor.java
  57. 3 2
      liteflow-script-plugin/liteflow-script-python/src/main/java/com/yomahub/liteflow/script/python/PythonScriptExecutor.java
  58. 15 1
      liteflow-script-plugin/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java
  59. 33 15
      liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonPathContentParser.java
  60. 11 0
      liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java
  61. 1 0
      liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java
  62. 7 0
      liteflow-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
  63. 1 0
      liteflow-spring-boot-starter/src/main/resources/META-INF/liteflow-default.properties
  64. 2 0
      liteflow-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  65. 40 14
      liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringPathContentParser.java
  66. 41 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELDeclMultiSpringbootTest.java
  67. 28 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CmpConfig.java
  68. 2 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/monitorFile/application.properties
  69. 7 0
      liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/monitorFile/flow.el.xml
  70. 40 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELDeclSpringbootTest.java
  71. 24 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java
  72. 25 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java
  73. 25 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java
  74. 1 1
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/refreshRule/RefreshRuleELDeclSpringbootTest.java
  75. 2 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/monitorFile/application.properties
  76. 7 0
      liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/monitorFile/flow.el.xml
  77. 40 0
      liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/LiteflowMonitorFileTest.java
  78. 18 0
      liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java
  79. 19 0
      liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java
  80. 19 0
      liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java
  81. 13 0
      liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/monitorFile/flow.el.xml
  82. 55 0
      liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/java/com/yomahub/liteflow/test/script/graaljs/contextbean/LiteFlowScriptContextbeanGraaljsTest.java
  83. 27 0
      liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/java/com/yomahub/liteflow/test/script/graaljs/contextbean/bean/CheckContext.java
  84. 36 0
      liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/java/com/yomahub/liteflow/test/script/graaljs/contextbean/bean/Order2Context.java
  85. 39 0
      liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/java/com/yomahub/liteflow/test/script/graaljs/contextbean/bean/OrderContext.java
  86. 20 0
      liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/java/com/yomahub/liteflow/test/script/graaljs/contextbean/cmp/ACmp.java
  87. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/java/com/yomahub/liteflow/test/script/graaljs/contextbean/cmp/BCmp.java
  88. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/java/com/yomahub/liteflow/test/script/graaljs/contextbean/cmp/CCmp.java
  89. 1 0
      liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/resources/contextbean/application.properties
  90. 30 0
      liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/resources/contextbean/flow.xml
  91. 55 0
      liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/contextbean/LiteFlowScriptContextbeanGroovyELTest.java
  92. 27 0
      liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/contextbean/bean/CheckContext.java
  93. 36 0
      liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/contextbean/bean/Order2Context.java
  94. 39 0
      liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/contextbean/bean/OrderContext.java
  95. 20 0
      liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/contextbean/cmp/ACmp.java
  96. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/contextbean/cmp/BCmp.java
  97. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/contextbean/cmp/CCmp.java
  98. 1 0
      liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/contextbean/application.properties
  99. 33 0
      liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/contextbean/flow.xml
  100. 55 0
      liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/contextbean/LiteFlowScriptContextbeanJavaScriptTest.java

+ 2 - 2
README.zh-CN.md

@@ -11,7 +11,7 @@ LiteFlow是一个轻量且强大的国产规则引擎框架,可用于复杂的
 
 
 LiteFlow于2020年正式开源,2021年获得开源中国年度最受欢迎开源软件殊荣。于2022年获得Gitee最有价值开源项目(GVP)荣誉。是一个正处在高速发展中的开源项目。
 LiteFlow于2020年正式开源,2021年获得开源中国年度最受欢迎开源软件殊荣。于2022年获得Gitee最有价值开源项目(GVP)荣誉。是一个正处在高速发展中的开源项目。
 
 
-LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥有一个1800多人的使用者社区,在使用中碰到任何问题或者建议都可以在社区中反应。
+LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥有一个2500多人的使用者社区,在使用中碰到任何问题或者建议都可以在社区中反应。
 
 
 你在官网中可以找到加入社区的方式!
 你在官网中可以找到加入社区的方式!
 
 
@@ -52,7 +52,7 @@ LiteFlow利用规则表达式为驱动引擎,去驱动你定义的组件。你
 
 
 LiteFlow拥有极其详细易懂的文档体系,能帮助你解决在使用框架的时候95%以上的问题。
 LiteFlow拥有极其详细易懂的文档体系,能帮助你解决在使用框架的时候95%以上的问题。
 
 
-目前为止,LiteFlow拥有800多个测试用例,并且不断在增加中。完备的文档+覆盖全面的测试用例保障了LiteFlow框架的稳定性!
+目前为止,LiteFlow拥有900多个测试用例,并且不断在增加中。完备的文档+覆盖全面的测试用例保障了LiteFlow框架的稳定性!
 
 
 LiteFlow期待你的了解!
 LiteFlow期待你的了解!
 
 

+ 4 - 0
liteflow-core/pom.xml

@@ -50,5 +50,9 @@
 			<groupId>commons-beanutils</groupId>
 			<groupId>commons-beanutils</groupId>
 			<artifactId>commons-beanutils</artifactId>
 			<artifactId>commons-beanutils</artifactId>
 		</dependency>
 		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+		</dependency>
 	</dependencies>
 	</dependencies>
 </project>
 </project>

+ 11 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java

@@ -7,6 +7,7 @@ import com.yomahub.liteflow.enums.NodeTypeEnum;
 import com.yomahub.liteflow.exception.NodeBuildException;
 import com.yomahub.liteflow.exception.NodeBuildException;
 import com.yomahub.liteflow.flow.FlowBus;
 import com.yomahub.liteflow.flow.FlowBus;
 import com.yomahub.liteflow.flow.element.Node;
 import com.yomahub.liteflow.flow.element.Node;
+import com.yomahub.liteflow.monitor.MonitorFile;
 import com.yomahub.liteflow.spi.holder.PathContentParserHolder;
 import com.yomahub.liteflow.spi.holder.PathContentParserHolder;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
@@ -134,6 +135,10 @@ public class LiteFlowNodeBuilder {
             List<String> scriptList = PathContentParserHolder.loadContextAware().parseContent(ListUtil.toList(filePath));
             List<String> scriptList = PathContentParserHolder.loadContextAware().parseContent(ListUtil.toList(filePath));
             String script = CollUtil.getFirst(scriptList);
             String script = CollUtil.getFirst(scriptList);
             setScript(script);
             setScript(script);
+
+            // 添加脚本文件监听
+            List<String> fileAbsolutePath = PathContentParserHolder.loadContextAware().getFileAbsolutePath(ListUtil.toList(filePath));
+            MonitorFile.getInstance().addMonitorFilePaths(fileAbsolutePath);
         } catch (Exception e) {
         } catch (Exception e) {
             String errMsg = StrUtil.format("An exception occurred while building the node[{}],{}", this.node.getId(), e.getMessage());
             String errMsg = StrUtil.format("An exception occurred while building the node[{}],{}", this.node.getId(), e.getMessage());
             throw new NodeBuildException(errMsg);
             throw new NodeBuildException(errMsg);
@@ -141,12 +146,17 @@ public class LiteFlowNodeBuilder {
         return this;
         return this;
     }
     }
 
 
+    public LiteFlowNodeBuilder setLanguage(String language) {
+        this.node.setLanguage(language);
+        return this;
+    }
+
     public void build() {
     public void build() {
         checkBuild();
         checkBuild();
         try {
         try {
             // 用于处理脚本 node
             // 用于处理脚本 node
            if (this.node.getType().isScript()){
            if (this.node.getType().isScript()){
-               FlowBus.addScriptNode(this.node.getId(), this.node.getName(), this.node.getType(), this.node.getScript());
+               FlowBus.addScriptNode(this.node.getId(), this.node.getName(), this.node.getType(), this.node.getScript(), this.node.getLanguage());
            }
            }
            // 用于处理普通 node
            // 用于处理普通 node
            else{
            else{

+ 6 - 5
liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java

@@ -59,6 +59,12 @@ public class LiteFlowChainELBuilder {
         EXPRESS_RUNNER.addFunction(ChainConstant.PRE, new PreOperator());
         EXPRESS_RUNNER.addFunction(ChainConstant.PRE, new PreOperator());
         EXPRESS_RUNNER.addFunction(ChainConstant.FINALLY, new FinallyOperator());
         EXPRESS_RUNNER.addFunction(ChainConstant.FINALLY, new FinallyOperator());
         EXPRESS_RUNNER.addFunction(ChainConstant.IF, new IfOperator());
         EXPRESS_RUNNER.addFunction(ChainConstant.IF, new IfOperator());
+        EXPRESS_RUNNER.addFunction(ChainConstant.NODE.toUpperCase(), new NodeOperator());
+        EXPRESS_RUNNER.addFunction(ChainConstant.NODE, new NodeOperator());
+        EXPRESS_RUNNER.addFunction(ChainConstant.FOR, new ForOperator());
+        EXPRESS_RUNNER.addFunction(ChainConstant.WHILE, new WhileOperator());
+        EXPRESS_RUNNER.addFunction(ChainConstant.ITERATOR, new IteratorOperator());
+        EXPRESS_RUNNER.addFunction(ChainConstant.CATCH, new CatchOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELSE, Object.class, new ElseOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELSE, Object.class, new ElseOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELIF, Object.class, new ElifOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELIF, Object.class, new ElifOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO, Object.class, new ToOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO, Object.class, new ToOperator());
@@ -69,11 +75,6 @@ public class LiteFlowChainELBuilder {
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ID, Object.class, new IdOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ID, Object.class, new IdOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.IGNORE_ERROR, Object.class, new IgnoreErrorOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.IGNORE_ERROR, Object.class, new IgnoreErrorOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.THREAD_POOL, Object.class, new ThreadPoolOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.THREAD_POOL, Object.class, new ThreadPoolOperator());
-        EXPRESS_RUNNER.addFunction(ChainConstant.NODE.toUpperCase(), new NodeOperator());
-        EXPRESS_RUNNER.addFunction(ChainConstant.NODE, new NodeOperator());
-        EXPRESS_RUNNER.addFunction(ChainConstant.FOR, new ForOperator());
-        EXPRESS_RUNNER.addFunction(ChainConstant.WHILE, new WhileOperator());
-        EXPRESS_RUNNER.addFunction(ChainConstant.ITERATOR, new IteratorOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DO, Object.class, new DoOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DO, Object.class, new DoOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BREAK, Object.class, new BreakOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BREAK, Object.class, new BreakOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DATA, Object.class, new DataOperator());
         EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DATA, Object.class, new DataOperator());

+ 26 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/CatchOperator.java

@@ -0,0 +1,26 @@
+package com.yomahub.liteflow.builder.el.operator;
+
+import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
+import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
+import com.yomahub.liteflow.flow.element.Executable;
+import com.yomahub.liteflow.flow.element.condition.CatchCondition;
+
+/**
+ * EL规则中的CATCH的操作符
+ * 用法:CATCH...DO...
+ * @author Bryan.Zhang
+ * @since 2.10.0
+ */
+public class CatchOperator extends BaseOperator<CatchCondition> {
+    @Override
+    public CatchCondition build(Object[] objects) throws Exception {
+        OperatorHelper.checkObjectSizeEq(objects, 1);
+
+        Executable catchItem = OperatorHelper.convert(objects[0], Executable.class);
+
+        CatchCondition catchCondition = new CatchCondition();
+        catchCondition.setCatchItem(catchItem);
+
+        return catchCondition;
+    }
+}

+ 26 - 13
liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/DoOperator.java

@@ -1,33 +1,46 @@
 package com.yomahub.liteflow.builder.el.operator;
 package com.yomahub.liteflow.builder.el.operator;
 
 
-import cn.hutool.core.collection.ListUtil;
+import com.ql.util.express.exception.QLException;
 import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
 import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
 import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
 import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
 import com.yomahub.liteflow.flow.element.Executable;
 import com.yomahub.liteflow.flow.element.Executable;
+import com.yomahub.liteflow.flow.element.condition.CatchCondition;
+import com.yomahub.liteflow.flow.element.condition.Condition;
 import com.yomahub.liteflow.flow.element.condition.LoopCondition;
 import com.yomahub.liteflow.flow.element.condition.LoopCondition;
 
 
 /**
 /**
  * EL规则中的DO的操作符
  * EL规则中的DO的操作符
- * 有种用法
+ * 有种用法
  * FOR...DO...BREAK
  * FOR...DO...BREAK
  * WHILE...DO...BREAK
  * WHILE...DO...BREAK
+ * CATCH...DO
  *
  *
  * @author Bryan.Zhang
  * @author Bryan.Zhang
  * @since 2.9.0
  * @since 2.9.0
  */
  */
-public class DoOperator extends BaseOperator<LoopCondition> {
+public class DoOperator extends BaseOperator<Condition> {
     @Override
     @Override
-    public LoopCondition build(Object[] objects) throws Exception {
+    public Condition build(Object[] objects) throws Exception {
         OperatorHelper.checkObjectSizeEqTwo(objects);
         OperatorHelper.checkObjectSizeEqTwo(objects);
 
 
-        //DO关键字有可能用在FOR后面,也有可能用于WHILE后面,所以这里要进行判断是不是这两种类型的超类LoopCondition
-        String errorMsg = "The caller must be ForCondition or WhileCondition item";
-        LoopCondition condition = OperatorHelper.convert(objects[0], LoopCondition.class, errorMsg);
-
-        //获得需要执行的可执行表达式
-        Executable doExecutableItem = OperatorHelper.convert(objects[1], Executable.class);
-        condition.setExecutableList(ListUtil.toList(doExecutableItem));
-
-        return condition;
+        if (objects[0] instanceof CatchCondition){
+            String errorMsg = "The caller must be CatchCondition item";
+            CatchCondition condition = OperatorHelper.convert(objects[0], CatchCondition.class, errorMsg);
+            //获得需要执行的可执行表达式
+            Executable doExecutableItem = OperatorHelper.convert(objects[1], Executable.class);
+            condition.setDoItem(doExecutableItem);
+            return condition;
+        }else if(objects[0] instanceof LoopCondition){
+            String errorMsg = "The caller must be LoopCondition item";
+            //DO关键字有可能用在FOR后面,也有可能用于WHILE后面,所以这里要进行判断是不是这两种类型的超类LoopCondition
+            LoopCondition condition = OperatorHelper.convert(objects[0], LoopCondition.class, errorMsg);
+            //获得需要执行的可执行表达式
+            Executable doExecutableItem = OperatorHelper.convert(objects[1], Executable.class);
+            condition.setDoExecutor(doExecutableItem);
+            return condition;
+        }else{
+            String errorMsg = "The caller must be LoopCondition or CatchCondition item";
+            throw new QLException(errorMsg);
+        }
     }
     }
 }
 }

+ 1 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ElifOperator.java

@@ -35,7 +35,7 @@ public class ElifOperator extends BaseOperator<IfCondition> {
 
 
 		//构建一个内部的IfCondition
 		//构建一个内部的IfCondition
 		IfCondition ifConditionItem = new IfCondition();
 		IfCondition ifConditionItem = new IfCondition();
-		ifConditionItem.setExecutableList(ListUtil.toList(ifNode));
+		ifConditionItem.setIfNode(ifNode);
 		ifConditionItem.setTrueCaseExecutableItem(trueCaseExecutableItem);
 		ifConditionItem.setTrueCaseExecutableItem(trueCaseExecutableItem);
 
 
 		//因为可能会有多个ELIF,所以每一次拿到的caller总是最开始大的if,需要遍历到没有falseCaseExecutable的地方。
 		//因为可能会有多个ELIF,所以每一次拿到的caller总是最开始大的if,需要遍历到没有falseCaseExecutable的地方。

+ 1 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IfOperator.java

@@ -37,7 +37,7 @@ public class IfOperator extends BaseOperator<IfCondition> {
         }
         }
 
 
         IfCondition ifCondition = new IfCondition();
         IfCondition ifCondition = new IfCondition();
-        ifCondition.setExecutableList(ListUtil.toList(ifNode));
+        ifCondition.setIfNode(ifNode);
         ifCondition.setTrueCaseExecutableItem(trueCaseExecutableItem);
         ifCondition.setTrueCaseExecutableItem(trueCaseExecutableItem);
         ifCondition.setFalseCaseExecutableItem(falseCaseExecutableItem);
         ifCondition.setFalseCaseExecutableItem(falseCaseExecutableItem);
         return ifCondition;
         return ifCondition;

+ 14 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/builder/prop/NodePropBean.java

@@ -35,6 +35,11 @@ public class NodePropBean {
 	 */
 	 */
 	String file;
 	String file;
 
 
+	/**
+	 * 脚本语言
+	 */
+	String language;
+
 	public String getId() {
 	public String getId() {
 		return id;
 		return id;
 	}
 	}
@@ -88,4 +93,13 @@ public class NodePropBean {
 		this.file = file;
 		this.file = file;
 		return this;
 		return this;
 	}
 	}
+
+	public String getLanguage() {
+		return language;
+	}
+
+	public NodePropBean setLanguage(String language) {
+		this.language = language;
+		return this;
+	}
 }
 }

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

@@ -23,6 +23,8 @@ public interface ChainConstant {
 
 
     String NAME = "name";
     String NAME = "name";
 
 
+    String LANGUAGE = "language";
+
     String VALUE = "value";
     String VALUE = "value";
 
 
     String ANY = "any";
     String ANY = "any";
@@ -70,4 +72,6 @@ public interface ChainConstant {
     String CURR_CHAIN_ID = "currChainId";
     String CURR_CHAIN_ID = "currChainId";
 
 
     String DEFAULT = "DEFAULT";
     String DEFAULT = "DEFAULT";
+
+    String CATCH = "CATCH";
 }
 }

+ 25 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/context/ContextBean.java

@@ -0,0 +1,25 @@
+package com.yomahub.liteflow.context;
+
+import com.yomahub.liteflow.annotation.AliasFor;
+
+import java.lang.annotation.*;
+
+/**
+ * @description 用于标注上下文bean的别名,以便在脚本或者组件中通过别名来获取上下文对象
+ * @since 2.9.7
+ * @author Tingliang Wang
+ * @createTime 2023/2/6 15:06
+ * @update: [序号][日期YYYY-MM-DD] [更改人姓名][变更描述]
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface ContextBean {
+    @AliasFor("name")
+    String value() default "";
+
+    @AliasFor("value")
+    String name() default "";
+
+}

+ 53 - 24
liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java

@@ -18,6 +18,7 @@ import com.yomahub.liteflow.flow.LiteflowResponse;
 import com.yomahub.liteflow.flow.element.Chain;
 import com.yomahub.liteflow.flow.element.Chain;
 import com.yomahub.liteflow.flow.element.Node;
 import com.yomahub.liteflow.flow.element.Node;
 import com.yomahub.liteflow.flow.id.IdGeneratorHolder;
 import com.yomahub.liteflow.flow.id.IdGeneratorHolder;
+import com.yomahub.liteflow.monitor.MonitorFile;
 import com.yomahub.liteflow.parser.base.FlowParser;
 import com.yomahub.liteflow.parser.base.FlowParser;
 import com.yomahub.liteflow.parser.factory.FlowParserProvider;
 import com.yomahub.liteflow.parser.factory.FlowParserProvider;
 import com.yomahub.liteflow.parser.spi.ParserClassNameSpi;
 import com.yomahub.liteflow.parser.spi.ParserClassNameSpi;
@@ -27,6 +28,7 @@ import com.yomahub.liteflow.slot.DataBus;
 import com.yomahub.liteflow.slot.DefaultContext;
 import com.yomahub.liteflow.slot.DefaultContext;
 import com.yomahub.liteflow.slot.Slot;
 import com.yomahub.liteflow.slot.Slot;
 import com.yomahub.liteflow.spi.holder.ContextCmpInitHolder;
 import com.yomahub.liteflow.spi.holder.ContextCmpInitHolder;
+import com.yomahub.liteflow.spi.holder.PathContentParserHolder;
 import com.yomahub.liteflow.thread.ExecutorHelper;
 import com.yomahub.liteflow.thread.ExecutorHelper;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
@@ -89,11 +91,11 @@ public class FlowExecutor {
             //所有的Parser的SPI实现都是以custom形式放入的,且只支持xml形式
             //所有的Parser的SPI实现都是以custom形式放入的,且只支持xml形式
             ServiceLoader<ParserClassNameSpi> loader = ServiceLoader.load(ParserClassNameSpi.class);
             ServiceLoader<ParserClassNameSpi> loader = ServiceLoader.load(ParserClassNameSpi.class);
             Iterator<ParserClassNameSpi> it = loader.iterator();
             Iterator<ParserClassNameSpi> it = loader.iterator();
-            if (it.hasNext()){
+            if (it.hasNext()) {
                 ParserClassNameSpi parserClassNameSpi = it.next();
                 ParserClassNameSpi parserClassNameSpi = it.next();
                 ruleSource = "el_xml:" + parserClassNameSpi.getSpiClassName();
                 ruleSource = "el_xml:" + parserClassNameSpi.getSpiClassName();
                 liteflowConfig.setRuleSource(ruleSource);
                 liteflowConfig.setRuleSource(ruleSource);
-            }else{
+            } else {
                 //ruleSource为空,而且没有spi形式的扩展,那么说明真的没有ruleSource
                 //ruleSource为空,而且没有spi形式的扩展,那么说明真的没有ruleSource
                 //这种情况有可能是基于代码动态构建的
                 //这种情况有可能是基于代码动态构建的
                 return;
                 return;
@@ -124,6 +126,7 @@ public class FlowExecutor {
 
 
                 //支持多类型的配置文件,分别解析
                 //支持多类型的配置文件,分别解析
                 if (BooleanUtil.isTrue(liteflowConfig.isSupportMultipleType())) {
                 if (BooleanUtil.isTrue(liteflowConfig.isSupportMultipleType())) {
+                    // 解析文件
                     parser.parseMain(ListUtil.toList(path));
                     parser.parseMain(ListUtil.toList(path));
                 }
                 }
             } catch (CyclicDependencyException e) {
             } catch (CyclicDependencyException e) {
@@ -148,6 +151,7 @@ public class FlowExecutor {
             //进行多个配置文件的一起解析
             //进行多个配置文件的一起解析
             try {
             try {
                 if (parser != null) {
                 if (parser != null) {
+                    // 解析文件
                     parser.parseMain(rulePathList);
                     parser.parseMain(rulePathList);
                 } else {
                 } else {
                     throw new ConfigErrorException("parse error, please check liteflow config property");
                     throw new ConfigErrorException("parse error, please check liteflow config property");
@@ -167,30 +171,44 @@ public class FlowExecutor {
         }
         }
 
 
         //如果是ruleSource方式的,最后判断下有没有解析出来,如果没有解析出来则报错
         //如果是ruleSource方式的,最后判断下有没有解析出来,如果没有解析出来则报错
-        if (StrUtil.isBlank(liteflowConfig.getRuleSourceExtData()) && MapUtil.isEmpty(liteflowConfig.getRuleSourceExtDataMap())){
-            if (FlowBus.getChainMap().isEmpty()){
+        if (StrUtil.isBlank(liteflowConfig.getRuleSourceExtData()) && MapUtil.isEmpty(liteflowConfig.getRuleSourceExtDataMap())) {
+            if (FlowBus.getChainMap().isEmpty()) {
                 String errMsg = StrUtil.format("no valid rule config found in rule path [{}]", liteflowConfig.getRuleSource());
                 String errMsg = StrUtil.format("no valid rule config found in rule path [{}]", liteflowConfig.getRuleSource());
                 throw new ConfigErrorException(errMsg);
                 throw new ConfigErrorException(errMsg);
             }
             }
         }
         }
 
 
         //执行钩子
         //执行钩子
-        if(hook){
+        if (hook) {
             FlowInitHook.executeHook();
             FlowInitHook.executeHook();
         }
         }
+
+        // 文件监听
+        if (liteflowConfig.getEnableMonitorFile()) {
+            try{
+                addMonitorFilePaths(rulePathList);
+                MonitorFile.getInstance().create();
+            }catch (Exception e){
+                String errMsg = StrUtil.format("file monitor init error for path:{}", rulePathList);
+                throw new MonitorFileInitErrorException(errMsg);
+            }
+
+        }
     }
     }
 
 
     //此方法就是从原有的配置源主动拉取新的进行刷新
     //此方法就是从原有的配置源主动拉取新的进行刷新
     //和FlowBus.refreshFlowMetaData的区别就是一个为主动拉取,一个为被动监听到新的内容进行刷新
     //和FlowBus.refreshFlowMetaData的区别就是一个为主动拉取,一个为被动监听到新的内容进行刷新
     public void reloadRule() {
     public void reloadRule() {
+        long start = System.currentTimeMillis();
         init(false);
         init(false);
+        LOG.info("reload rules takes {}ms", System.currentTimeMillis() - start);
     }
     }
 
 
     //隐式流程的调用方法
     //隐式流程的调用方法
     @Deprecated
     @Deprecated
     public void invoke(String chainId, Object param, Integer slotIndex) throws Exception {
     public void invoke(String chainId, Object param, Integer slotIndex) throws Exception {
         LiteflowResponse response = this.invoke2Resp(chainId, param, slotIndex, InnerChainTypeEnum.IN_SYNC);
         LiteflowResponse response = this.invoke2Resp(chainId, param, slotIndex, InnerChainTypeEnum.IN_SYNC);
-        if (!response.isSuccess()){
+        if (!response.isSuccess()) {
             throw response.getCause();
             throw response.getCause();
         }
         }
     }
     }
@@ -198,7 +216,7 @@ public class FlowExecutor {
     @Deprecated
     @Deprecated
     public void invokeInAsync(String chainId, Object param, Integer slotIndex) throws Exception {
     public void invokeInAsync(String chainId, Object param, Integer slotIndex) throws Exception {
         LiteflowResponse response = this.invoke2Resp(chainId, param, slotIndex, InnerChainTypeEnum.IN_ASYNC);
         LiteflowResponse response = this.invoke2Resp(chainId, param, slotIndex, InnerChainTypeEnum.IN_ASYNC);
-        if (!response.isSuccess()){
+        if (!response.isSuccess()) {
             throw response.getCause();
             throw response.getCause();
         }
         }
     }
     }
@@ -240,7 +258,7 @@ public class FlowExecutor {
     //调用一个流程并返回Future<LiteflowResponse>,允许多上下文的传入
     //调用一个流程并返回Future<LiteflowResponse>,允许多上下文的传入
     public Future<LiteflowResponse> execute2Future(String chainId, Object param, Class<?>... contextBeanClazzArray) {
     public Future<LiteflowResponse> execute2Future(String chainId, Object param, Class<?>... contextBeanClazzArray) {
         return ExecutorHelper.loadInstance().buildMainExecutor(liteflowConfig.getMainExecutorClass()).submit(()
         return ExecutorHelper.loadInstance().buildMainExecutor(liteflowConfig.getMainExecutorClass()).submit(()
-                -> FlowExecutorHolder.loadInstance().execute2Resp(chainId, param, contextBeanClazzArray,null));
+                -> FlowExecutorHolder.loadInstance().execute2Resp(chainId, param, contextBeanClazzArray, null));
     }
     }
 
 
 
 
@@ -251,11 +269,11 @@ public class FlowExecutor {
 
 
     //调用一个流程,返回默认的上下文,适用于简单的调用
     //调用一个流程,返回默认的上下文,适用于简单的调用
     @Deprecated
     @Deprecated
-    public DefaultContext execute(String chainId, Object param) throws Exception{
+    public DefaultContext execute(String chainId, Object param) throws Exception {
         LiteflowResponse response = this.execute2Resp(chainId, param, DefaultContext.class);
         LiteflowResponse response = this.execute2Resp(chainId, param, DefaultContext.class);
-        if (!response.isSuccess()){
+        if (!response.isSuccess()) {
             throw response.getCause();
             throw response.getCause();
-        }else{
+        } else {
             return response.getFirstContextBean();
             return response.getFirstContextBean();
         }
         }
     }
     }
@@ -269,8 +287,8 @@ public class FlowExecutor {
     }
     }
 
 
     private LiteflowResponse invoke2Resp(String chainId,
     private LiteflowResponse invoke2Resp(String chainId,
-                                          Object param,
-                                          Integer slotIndex, InnerChainTypeEnum innerChainType) {
+                                         Object param,
+                                         Integer slotIndex, InnerChainTypeEnum innerChainType) {
         Slot slot = doExecute(chainId, param, null, null, slotIndex, innerChainType);
         Slot slot = doExecute(chainId, param, null, null, slotIndex, innerChainType);
         return LiteflowResponse.newInnerResponse(chainId, slot);
         return LiteflowResponse.newInnerResponse(chainId, slot);
     }
     }
@@ -288,9 +306,9 @@ public class FlowExecutor {
         //如果不是隐式流程,那么需要分配Slot
         //如果不是隐式流程,那么需要分配Slot
         if (innerChainType.equals(InnerChainTypeEnum.NONE) && ObjectUtil.isNull(slotIndex)) {
         if (innerChainType.equals(InnerChainTypeEnum.NONE) && ObjectUtil.isNull(slotIndex)) {
             //这里可以根据class分配,也可以根据bean去分配
             //这里可以根据class分配,也可以根据bean去分配
-            if (ArrayUtil.isNotEmpty(contextBeanClazzArray)){
+            if (ArrayUtil.isNotEmpty(contextBeanClazzArray)) {
                 slotIndex = DataBus.offerSlotByClass(ListUtil.toList(contextBeanClazzArray));
                 slotIndex = DataBus.offerSlotByClass(ListUtil.toList(contextBeanClazzArray));
-            }else{
+            } else {
                 slotIndex = DataBus.offerSlotByBean(ListUtil.toList(contextBeanArray));
                 slotIndex = DataBus.offerSlotByBean(ListUtil.toList(contextBeanArray));
             }
             }
             if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())) {
             if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())) {
@@ -311,7 +329,7 @@ public class FlowExecutor {
         //如果是隐式流程,事先把subException给置空,然后把隐式流程的chainId放入slot元数据中
         //如果是隐式流程,事先把subException给置空,然后把隐式流程的chainId放入slot元数据中
         //我知道这在多线程调用隐式流程中会有问题。但是考虑到这种场景的不会多,也有其他的转换方式。
         //我知道这在多线程调用隐式流程中会有问题。但是考虑到这种场景的不会多,也有其他的转换方式。
         //所以暂且这么做,以后再优化
         //所以暂且这么做,以后再优化
-        if (!innerChainType.equals(InnerChainTypeEnum.NONE)){
+        if (!innerChainType.equals(InnerChainTypeEnum.NONE)) {
             slot.removeSubException(chainId);
             slot.removeSubException(chainId);
             slot.addSubChain(chainId);
             slot.addSubChain(chainId);
         }
         }
@@ -326,9 +344,9 @@ public class FlowExecutor {
         if (ObjectUtil.isNotNull(param)) {
         if (ObjectUtil.isNotNull(param)) {
             if (innerChainType.equals(InnerChainTypeEnum.NONE)) {
             if (innerChainType.equals(InnerChainTypeEnum.NONE)) {
                 slot.setRequestData(param);
                 slot.setRequestData(param);
-            } else if(innerChainType.equals(InnerChainTypeEnum.IN_SYNC)){
+            } else if (innerChainType.equals(InnerChainTypeEnum.IN_SYNC)) {
                 slot.setChainReqData(chainId, param);
                 slot.setChainReqData(chainId, param);
-            } else if(innerChainType.equals(InnerChainTypeEnum.IN_ASYNC)){
+            } else if (innerChainType.equals(InnerChainTypeEnum.IN_ASYNC)) {
                 slot.setChainReqData2Queue(chainId, param);
                 slot.setChainReqData2Queue(chainId, param);
             }
             }
         }
         }
@@ -351,15 +369,15 @@ public class FlowExecutor {
         } catch (Exception e) {
         } catch (Exception e) {
             if (ObjectUtil.isNotNull(chain)) {
             if (ObjectUtil.isNotNull(chain)) {
                 String errMsg = StrUtil.format("[{}]:chain[{}] execute error on slot[{}]", slot.getRequestId(), chain.getChainName(), slotIndex);
                 String errMsg = StrUtil.format("[{}]:chain[{}] execute error on slot[{}]", slot.getRequestId(), chain.getChainName(), slotIndex);
-                if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())){
+                if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())) {
                     LOG.error(errMsg, e);
                     LOG.error(errMsg, e);
-                }else{
+                } else {
                     LOG.error(errMsg);
                     LOG.error(errMsg);
                 }
                 }
-            }else{
-                if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())){
+            } else {
+                if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())) {
                     LOG.error(e.getMessage(), e);
                     LOG.error(e.getMessage(), e);
-                }else{
+                } else {
                     LOG.error(e.getMessage());
                     LOG.error(e.getMessage());
                 }
                 }
             }
             }
@@ -368,7 +386,7 @@ public class FlowExecutor {
             //如果是隐式流程,则需要设置到隐式流程的exception属性里
             //如果是隐式流程,则需要设置到隐式流程的exception属性里
             if (innerChainType.equals(InnerChainTypeEnum.NONE)) {
             if (innerChainType.equals(InnerChainTypeEnum.NONE)) {
                 slot.setException(e);
                 slot.setException(e);
-            }else{
+            } else {
                 slot.setSubException(chainId, e);
                 slot.setSubException(chainId, e);
             }
             }
         } finally {
         } finally {
@@ -389,4 +407,15 @@ public class FlowExecutor {
         //把liteFlowConfig设到LiteFlowGetter中去
         //把liteFlowConfig设到LiteFlowGetter中去
         LiteflowConfigGetter.setLiteflowConfig(liteflowConfig);
         LiteflowConfigGetter.setLiteflowConfig(liteflowConfig);
     }
     }
+
+    /**
+     * 添加监听文件路径
+     *
+     * @param pathList 文件路径
+     */
+    private void addMonitorFilePaths(List<String> pathList) throws Exception {
+        // 添加规则文件监听
+        List<String> fileAbsolutePath = PathContentParserHolder.loadContextAware().getFileAbsolutePath(pathList);
+        MonitorFile.getInstance().addMonitorFilePaths(fileAbsolutePath);
+    }
 }
 }

+ 3 - 3
liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptBreakComponent.java

@@ -19,11 +19,11 @@ public class ScriptBreakComponent extends NodeBreakComponent implements ScriptCo
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setTag(this.getTag());
         wrap.setTag(this.getTag());
         wrap.setCmpData(this.getCmpData(Map.class));
         wrap.setCmpData(this.getCmpData(Map.class));
-        return (boolean) ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
+        return (boolean) ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
     }
     }
 
 
     @Override
     @Override
-    public void loadScript(String script) {
-        ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
+    public void loadScript(String script, String language) {
+        ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
     }
     }
 }
 }

+ 3 - 3
liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptCommonComponent.java

@@ -24,12 +24,12 @@ public class ScriptCommonComponent extends NodeComponent implements ScriptCompon
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setTag(this.getTag());
         wrap.setTag(this.getTag());
         wrap.setCmpData(this.getCmpData(Map.class));
         wrap.setCmpData(this.getCmpData(Map.class));
-        ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
+        ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
     }
     }
 
 
     @Override
     @Override
-    public void loadScript(String script) {
+    public void loadScript(String script, String language) {
         log.info("load script for component[{}]", getDisplayName());
         log.info("load script for component[{}]", getDisplayName());
-        ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
+        ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
     }
     }
 }
 }

+ 1 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptComponent.java

@@ -28,5 +28,5 @@ public interface ScriptComponent {
      * 加载脚本
      * 加载脚本
      * @param script
      * @param script
      */
      */
-    void loadScript(String script);
+    void loadScript(String script, String language);
 }
 }

+ 3 - 3
liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptForComponent.java

@@ -19,11 +19,11 @@ public class ScriptForComponent extends NodeForComponent implements ScriptCompon
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setTag(this.getTag());
         wrap.setTag(this.getTag());
         wrap.setCmpData(this.getCmpData(Map.class));
         wrap.setCmpData(this.getCmpData(Map.class));
-        return (int) ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
+        return (int) ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
     }
     }
 
 
     @Override
     @Override
-    public void loadScript(String script) {
-        ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
+    public void loadScript(String script, String language) {
+        ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
     }
     }
 }
 }

+ 3 - 3
liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptIfComponent.java

@@ -19,11 +19,11 @@ public class ScriptIfComponent extends NodeIfComponent implements ScriptComponen
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setTag(this.getTag());
         wrap.setTag(this.getTag());
         wrap.setCmpData(this.getCmpData(Map.class));
         wrap.setCmpData(this.getCmpData(Map.class));
-        return (boolean)ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
+        return (boolean)ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
     }
     }
 
 
     @Override
     @Override
-    public void loadScript(String script) {
-        ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
+    public void loadScript(String script, String language) {
+        ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
     }
     }
 }
 }

+ 3 - 3
liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptSwitchComponent.java

@@ -20,11 +20,11 @@ public class ScriptSwitchComponent extends NodeSwitchComponent implements Script
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setTag(this.getTag());
         wrap.setTag(this.getTag());
         wrap.setCmpData(this.getCmpData(Map.class));
         wrap.setCmpData(this.getCmpData(Map.class));
-        return (String)ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
+        return (String)ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
     }
     }
 
 
     @Override
     @Override
-    public void loadScript(String script) {
-        ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
+    public void loadScript(String script, String language) {
+        ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
     }
     }
 }
 }

+ 3 - 3
liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptWhileComponent.java

@@ -20,11 +20,11 @@ public class ScriptWhileComponent extends NodeWhileComponent implements ScriptCo
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setSlotIndex(this.getSlotIndex());
         wrap.setTag(this.getTag());
         wrap.setTag(this.getTag());
         wrap.setCmpData(this.getCmpData(Map.class));
         wrap.setCmpData(this.getCmpData(Map.class));
-        return (boolean) ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
+        return (boolean) ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
     }
     }
 
 
     @Override
     @Override
-    public void loadScript(String script) {
-        ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
+    public void loadScript(String script, String language) {
+        ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
     }
     }
 }
 }

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

@@ -16,7 +16,9 @@ public enum ConditionTypeEnum {
 
 
     TYPE_WHILE("while", "while"),
     TYPE_WHILE("while", "while"),
 
 
-    TYPE_ITERATOR("iterator", "iterator")
+    TYPE_ITERATOR("iterator", "iterator"),
+
+    TYPE_CATCH("catch", "catch")
     ;
     ;
     private String type;
     private String type;
     private String name;
     private String name;

+ 44 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/enums/ScriptTypeEnum.java

@@ -0,0 +1,44 @@
+package com.yomahub.liteflow.enums;
+
+public enum ScriptTypeEnum {
+
+    GROOVY("groovy", "groovy"),
+    QLEXPRESS("qlexpress", "qlexpress"),
+    JS("javascript", "js"),
+    PYTHON("python", "python"),
+    LUA("luaj", "lua")
+    ;
+    private String engineName;
+
+    private String displayName;
+
+    ScriptTypeEnum(String engineName, String displayName) {
+        this.engineName = engineName;
+        this.displayName = displayName;
+    }
+
+    public String getEngineName() {
+        return engineName;
+    }
+
+    public void setEngineName(String engineName) {
+        this.engineName = engineName;
+    }
+
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    public void setDisplayName(String displayName) {
+        this.displayName = displayName;
+    }
+
+    public static ScriptTypeEnum getEnumByDisplayName(String displayName) {
+        for (ScriptTypeEnum e : ScriptTypeEnum.values()) {
+            if (e.getDisplayName().equals(displayName)) {
+                return e;
+            }
+        }
+        return null;
+    }
+}

+ 29 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/exception/CatchErrorException.java

@@ -0,0 +1,29 @@
+package com.yomahub.liteflow.exception;
+
+/**
+ * 类型错误异常
+ * @author Yun
+ */
+public class CatchErrorException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 异常信息
+     */
+    private String message;
+
+    public CatchErrorException(String message) {
+        this.message = message;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+}

+ 28 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/exception/MonitorFileInitErrorException.java

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

+ 8 - 10
liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java

@@ -106,7 +106,7 @@ public class FlowBus {
      * @param cmpClazz 节点组件类
      * @param cmpClazz 节点组件类
      */
      */
     public static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz) {
     public static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz) {
-        addNode(nodeId, name, type, cmpClazz, null);
+        addNode(nodeId, name, type, cmpClazz, null, null);
     }
     }
 
 
     /**
     /**
@@ -124,7 +124,7 @@ public class FlowBus {
         } catch (Exception e) {
         } catch (Exception e) {
             throw new ComponentCannotRegisterException(e.getMessage());
             throw new ComponentCannotRegisterException(e.getMessage());
         }
         }
-        addNode(nodeId, name, nodeType, cmpClazz, null);
+        addNode(nodeId, name, nodeType, cmpClazz, null, null);
     }
     }
 
 
     /**
     /**
@@ -135,11 +135,11 @@ public class FlowBus {
      * @param nodeType 节点类型
      * @param nodeType 节点类型
      * @param script   脚本
      * @param script   脚本
      */
      */
-    public static void addScriptNode(String nodeId, String name, NodeTypeEnum nodeType, String script) {
-        addNode(nodeId, name, nodeType, ScriptComponent.ScriptComponentClassMap.get(nodeType), script);
+    public static void addScriptNode(String nodeId, String name, NodeTypeEnum nodeType, String script, String language) {
+        addNode(nodeId, name, nodeType, ScriptComponent.ScriptComponentClassMap.get(nodeType), script, language);
     }
     }
 
 
-    private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script) {
+    private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script, String language) {
         try {
         try {
             //判断此类是否是声明式的组件,如果是声明式的组件,就用动态代理生成实例
             //判断此类是否是声明式的组件,如果是声明式的组件,就用动态代理生成实例
             //如果不是声明式的,就用传统的方式进行判断
             //如果不是声明式的,就用传统的方式进行判断
@@ -193,7 +193,8 @@ public class FlowBus {
                 if (type.isScript()) {
                 if (type.isScript()) {
                     if (StrUtil.isNotBlank(script)) {
                     if (StrUtil.isNotBlank(script)) {
                         node.setScript(script);
                         node.setScript(script);
-                        ((ScriptComponent) cmpInstance).loadScript(script);
+                        node.setLanguage(language);
+                        ((ScriptComponent) cmpInstance).loadScript(script, language);
                     } else {
                     } else {
                         String errorMsg = StrUtil.format("script for node[{}] is empty", nodeId);
                         String errorMsg = StrUtil.format("script for node[{}] is empty", nodeId);
                         throw new ScriptLoadException(errorMsg);
                         throw new ScriptLoadException(errorMsg);
@@ -244,10 +245,7 @@ public class FlowBus {
     public static void cleanScriptCache() {
     public static void cleanScriptCache() {
         //如果引入了脚本组件SPI,则还需要清理脚本的缓存
         //如果引入了脚本组件SPI,则还需要清理脚本的缓存
         try {
         try {
-            ScriptExecutor scriptExecutor = ScriptExecutorFactory.loadInstance().getScriptExecutor();
-            if (ObjectUtil.isNotNull(scriptExecutor)) {
-                scriptExecutor.cleanCache();
-            }
+            ScriptExecutorFactory.loadInstance().cleanScriptCache();
         } catch (ScriptSpiException ignored) {
         } catch (ScriptSpiException ignored) {
         }
         }
     }
     }

+ 1 - 3
liteflow-core/src/main/java/com/yomahub/liteflow/flow/LiteflowResponse.java

@@ -13,9 +13,7 @@ import java.util.Queue;
  * 执行结果封装类
  * 执行结果封装类
  * @author zend.wang
  * @author zend.wang
  */
  */
-public class LiteflowResponse implements Serializable {
-    
-    private static final long serialVersionUID = -2792556188993845048L;
+public class LiteflowResponse{
     
     
     private boolean success;
     private boolean success;
 
 

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

@@ -46,6 +46,8 @@ public class Node implements Executable,Cloneable{
 
 
 	private String script;
 	private String script;
 
 
+	private String language;
+
 	private NodeComponent instance;
 	private NodeComponent instance;
 
 
 	private String tag;
 	private String tag;
@@ -255,4 +257,12 @@ public class Node implements Executable,Cloneable{
 	public void removeCurrLoopObject(){
 	public void removeCurrLoopObject(){
 		this.currLoopObject.remove();
 		this.currLoopObject.remove();
 	}
 	}
+
+	public String getLanguage() {
+		return language;
+	}
+
+	public void setLanguage(String language) {
+		this.language = language;
+	}
 }
 }

+ 61 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/CatchCondition.java

@@ -0,0 +1,61 @@
+package com.yomahub.liteflow.flow.element.condition;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.enums.ConditionTypeEnum;
+import com.yomahub.liteflow.exception.CatchErrorException;
+import com.yomahub.liteflow.flow.element.Executable;
+import com.yomahub.liteflow.slot.DataBus;
+import com.yomahub.liteflow.slot.Slot;
+
+/**
+ * Catch Condition
+ * @author Bryan.Zhang
+ * @since 2.10.0
+ */
+public class CatchCondition extends Condition{
+
+    @Override
+    public void executeCondition(Integer slotIndex) throws Exception {
+        Slot slot = DataBus.getSlot(slotIndex);
+        try{
+            Executable catchExecutable = this.getCatchItem();
+            if (ObjectUtil.isNull(catchExecutable)){
+                String errorInfo = StrUtil.format("[{}]:no catch item find", slot.getRequestId());
+                throw new CatchErrorException(errorInfo);
+            }
+            catchExecutable.setCurrChainId(this.getCurrChainId());
+            catchExecutable.execute(slotIndex);
+        }catch (Exception e){
+            Executable doExecutable = this.getDoItem();
+            if (ObjectUtil.isNotNull(doExecutable)){
+                doExecutable.setCurrChainId(this.getCurrChainId());
+                doExecutable.execute(slotIndex);
+            }
+            //catch之后需要把exception给清除掉
+            //正如同java的catch一样,异常自己处理了,属于正常流程了,整个流程状态应该是成功的
+            DataBus.getSlot(slotIndex).removeException();
+        }
+    }
+
+    @Override
+    public ConditionTypeEnum getConditionType() {
+        return ConditionTypeEnum.TYPE_CATCH;
+    }
+
+    public Executable getCatchItem(){
+        return this.getExecutableOne(ConditionKey.CATCH_KEY);
+    }
+
+    public void setCatchItem(Executable executable){
+        this.addExecutable(ConditionKey.CATCH_KEY, executable);
+    }
+
+    public Executable getDoItem(){
+        return this.getExecutableOne(ConditionKey.DO_KEY);
+    }
+
+    public void setDoItem(Executable executable){
+        this.addExecutable(ConditionKey.DO_KEY, executable);
+    }
+}

+ 67 - 5
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/Condition.java

@@ -7,12 +7,20 @@
  */
  */
 package com.yomahub.liteflow.flow.element.condition;
 package com.yomahub.liteflow.flow.element.condition;
 
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.yomahub.liteflow.enums.ExecuteTypeEnum;
 import com.yomahub.liteflow.enums.ExecuteTypeEnum;
+import com.yomahub.liteflow.exception.ChainEndException;
 import com.yomahub.liteflow.flow.element.Executable;
 import com.yomahub.liteflow.flow.element.Executable;
 import com.yomahub.liteflow.enums.ConditionTypeEnum;
 import com.yomahub.liteflow.enums.ConditionTypeEnum;
+import com.yomahub.liteflow.slot.DataBus;
+import com.yomahub.liteflow.slot.Slot;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 
 
 /**
 /**
  * Condition的抽象类
  * Condition的抽象类
@@ -25,8 +33,7 @@ public abstract class Condition implements Executable{
 	/**
 	/**
 	 * 可执行元素的集合
 	 * 可执行元素的集合
 	 */
 	 */
-	private List<Executable> executableList = new ArrayList<>();
-
+	private final Map<String, List<Executable>> executableGroup = new HashMap<>();
 
 
 	/**
 	/**
 	 * 当前所在的ChainName
 	 * 当前所在的ChainName
@@ -34,6 +41,29 @@ public abstract class Condition implements Executable{
 	 */
 	 */
 	private String currChainId;
 	private String currChainId;
 
 
+	@Override
+	public void execute(Integer slotIndex) throws Exception {
+		try{
+			executeCondition(slotIndex);
+		}catch (ChainEndException e){
+			//这里单独catch ChainEndException是因为ChainEndException是用户自己setIsEnd抛出的异常
+			//是属于正常逻辑,所以会在FlowExecutor中判断。这里不作为异常处理
+			throw e;
+		}catch (Exception e){
+			Slot slot = DataBus.getSlot(slotIndex);
+			String chainId = this.getCurrChainId();
+			//这里事先取到exception set到slot里,为了方便finally取到exception
+			if (slot.isSubChain(chainId)){
+				slot.setSubException(chainId, e);
+			}else{
+				slot.setException(e);
+			}
+			throw e;
+		}
+	}
+
+	protected abstract void executeCondition(Integer slotIndex) throws Exception;
+
 	@Override
 	@Override
 	public ExecuteTypeEnum getExecuteType() {
 	public ExecuteTypeEnum getExecuteType() {
 		return ExecuteTypeEnum.CONDITION;
 		return ExecuteTypeEnum.CONDITION;
@@ -45,15 +75,44 @@ public abstract class Condition implements Executable{
 	}
 	}
 
 
 	public List<Executable> getExecutableList() {
 	public List<Executable> getExecutableList() {
+		return getExecutableList(ConditionKey.DEFAULT_KEY);
+	}
+
+	public List<Executable> getExecutableList(String groupKey) {
+		List<Executable> executableList = this.executableGroup.get(groupKey);
+		if (CollUtil.isEmpty(executableList)){
+			executableList = new ArrayList<>();
+		}
 		return executableList;
 		return executableList;
 	}
 	}
 
 
+	public Executable getExecutableOne(String groupKey) {
+		List<Executable> list = getExecutableList(groupKey);
+		if (CollUtil.isEmpty(list)){
+			return null;
+		}else{
+			return list.get(0);
+		}
+	}
+
 	public void setExecutableList(List<Executable> executableList) {
 	public void setExecutableList(List<Executable> executableList) {
-		this.executableList = executableList;
+		this.executableGroup.put(ConditionKey.DEFAULT_KEY, executableList);
 	}
 	}
 
 
 	public void addExecutable(Executable executable) {
 	public void addExecutable(Executable executable) {
-		this.executableList.add(executable);
+		addExecutable(ConditionKey.DEFAULT_KEY, executable);
+	}
+
+	public void addExecutable(String groupKey, Executable executable) {
+		if (ObjectUtil.isNull(executable)){
+			return;
+		}
+		List<Executable> executableList = this.executableGroup.get(groupKey);
+		if (CollUtil.isEmpty(executableList)){
+			this.executableGroup.put(groupKey, ListUtil.toList(executable));
+		}else{
+			this.executableGroup.get(groupKey).add(executable);
+		}
 	}
 	}
 
 
 	public abstract ConditionTypeEnum getConditionType();
 	public abstract ConditionTypeEnum getConditionType();
@@ -68,7 +127,6 @@ public abstract class Condition implements Executable{
 
 
 	/**
 	/**
 	 * 
 	 * 
-	 * @return
 	 * @deprecated 请使用 {@link #setCurrChainId(String)}
 	 * @deprecated 请使用 {@link #setCurrChainId(String)}
 	 */
 	 */
 	@Deprecated
 	@Deprecated
@@ -84,4 +142,8 @@ public abstract class Condition implements Executable{
 	public void setCurrChainId(String currChainId) {
 	public void setCurrChainId(String currChainId) {
 		this.currChainId = currChainId;
 		this.currChainId = currChainId;
 	}
 	}
+
+	public Map<String, List<Executable>> getExecutableGroup() {
+		return executableGroup;
+	}
 }
 }

+ 34 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ConditionKey.java

@@ -0,0 +1,34 @@
+package com.yomahub.liteflow.flow.element.condition;
+
+public interface ConditionKey {
+
+    String DEFAULT_KEY = "DEFAULT_KEY";
+
+    String FOR_KEY = "FOR_KEY";
+
+    String IF_KEY = "IF_KEY";
+
+    String IF_TRUE_CASE_KEY = "IF_TRUE_CASE_KEY";
+
+    String IF_FALSE_CASE_KEY = "IF_FALSE_CASE_KEY";
+
+    String ITERATOR_KEY = "ITERATOR_KEY";
+
+    String DO_KEY = "DO_KEY";
+
+    String BREAK_KEY = "BREAK_KEY";
+
+    String SWITCH_KEY = "SWITCH_KEY";
+
+    String SWITCH_TARGET_KEY = "SWITCH_TARGET_KEY";
+
+    String SWITCH_DEFAULT_KEY = "SWITCH_DEFAULT_KEY";
+
+    String PRE_KEY = "PRE_KEY";
+
+    String FINALLY_KEY = "FINALLY_KEY";
+
+    String WHILE_KEY = "WHILE_KEY";
+
+    String CATCH_KEY = "CATCH_KEY";
+}

+ 1 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/FinallyCondition.java

@@ -18,7 +18,7 @@ import com.yomahub.liteflow.flow.element.Executable;
 public class FinallyCondition extends Condition {
 public class FinallyCondition extends Condition {
 
 
 	@Override
 	@Override
-	public void execute(Integer slotIndex) throws Exception {
+	public void executeCondition(Integer slotIndex) throws Exception {
 		for(Executable executableItem : this.getExecutableList()){
 		for(Executable executableItem : this.getExecutableList()){
 			executableItem.setCurrChainId(this.getCurrChainId());
 			executableItem.setCurrChainId(this.getCurrChainId());
 			executableItem.execute(slotIndex);
 			executableItem.execute(slotIndex);

+ 14 - 7
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java

@@ -18,28 +18,35 @@ import com.yomahub.liteflow.util.LiteFlowProxyUtil;
  */
  */
 public class ForCondition extends LoopCondition{
 public class ForCondition extends LoopCondition{
 
 
-    private Node forNode;
-
     @Override
     @Override
-    public void execute(Integer slotIndex) throws Exception {
+    public void executeCondition(Integer slotIndex) throws Exception {
         Slot slot = DataBus.getSlot(slotIndex);
         Slot slot = DataBus.getSlot(slotIndex);
+        Node forNode = this.getForNode();
         if (ObjectUtil.isNull(forNode)){
         if (ObjectUtil.isNull(forNode)){
             String errorInfo = StrUtil.format("[{}]:no for-node found", slot.getRequestId());
             String errorInfo = StrUtil.format("[{}]:no for-node found", slot.getRequestId());
             throw new NoForNodeException(errorInfo);
             throw new NoForNodeException(errorInfo);
         }
         }
 
 
+        //先去判断isAccess方法,如果isAccess方法都返回false,整个FOR表达式不执行
+        if (!this.getForNode().isAccess(slotIndex)){
+            return;
+        }
+
         //执行forCount组件
         //执行forCount组件
         forNode.setCurrChainId(this.getCurrChainId());
         forNode.setCurrChainId(this.getCurrChainId());
         forNode.execute(slotIndex);
         forNode.execute(slotIndex);
 
 
         //这里可能会有spring代理过的bean,所以拿到user原始的class
         //这里可能会有spring代理过的bean,所以拿到user原始的class
-        Class<?> originalForCountClass = LiteFlowProxyUtil.getUserClass(this.forNode.getInstance().getClass());
+        Class<?> originalForCountClass = LiteFlowProxyUtil.getUserClass(forNode.getInstance().getClass());
         //获得循环次数
         //获得循环次数
         int forCount = slot.getForResult(originalForCountClass.getName());
         int forCount = slot.getForResult(originalForCountClass.getName());
 
 
         //获得要循环的可执行对象
         //获得要循环的可执行对象
         Executable executableItem = this.getDoExecutor();
         Executable executableItem = this.getDoExecutor();
 
 
+        //获取Break节点
+        Node breakNode = this.getBreakNode();
+
         //循环执行
         //循环执行
         for (int i = 0; i < forCount; i++) {
         for (int i = 0; i < forCount; i++) {
             executableItem.setCurrChainId(this.getCurrChainId());
             executableItem.setCurrChainId(this.getCurrChainId());
@@ -51,7 +58,7 @@ public class ForCondition extends LoopCondition{
                 breakNode.setCurrChainId(this.getCurrChainId());
                 breakNode.setCurrChainId(this.getCurrChainId());
                 setLoopIndex(breakNode, i);
                 setLoopIndex(breakNode, i);
                 breakNode.execute(slotIndex);
                 breakNode.execute(slotIndex);
-                Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getInstance().getClass());
+                Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(breakNode.getInstance().getClass());
                 boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
                 boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
                 if (isBreak){
                 if (isBreak){
                     break;
                     break;
@@ -66,10 +73,10 @@ public class ForCondition extends LoopCondition{
     }
     }
 
 
     public Node getForNode() {
     public Node getForNode() {
-        return forNode;
+        return (Node) this.getExecutableOne(ConditionKey.FOR_KEY);
     }
     }
 
 
     public void setForNode(Node forNode) {
     public void setForNode(Node forNode) {
-        this.forNode = forNode;
+        this.addExecutable(ConditionKey.FOR_KEY, forNode);
     }
     }
 }
 }

+ 19 - 11
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IfCondition.java

@@ -20,13 +20,14 @@ import com.yomahub.liteflow.util.LiteFlowProxyUtil;
  */
  */
 public class IfCondition extends Condition {
 public class IfCondition extends Condition {
 
 
-    private Executable trueCaseExecutableItem;
-
-    private Executable falseCaseExecutableItem;
-
     @Override
     @Override
-    public void execute(Integer slotIndex) throws Exception {
+    public void executeCondition(Integer slotIndex) throws Exception {
         if (ListUtil.toList(NodeTypeEnum.IF, NodeTypeEnum.IF_SCRIPT).contains(getIfNode().getType())){
         if (ListUtil.toList(NodeTypeEnum.IF, NodeTypeEnum.IF_SCRIPT).contains(getIfNode().getType())){
+            //先去判断isAccess方法,如果isAccess方法都返回false,整个IF表达式不执行
+            if (!this.getIfNode().isAccess(slotIndex)){
+                return;
+            }
+
             //先执行IF节点
             //先执行IF节点
             this.getIfNode().setCurrChainId(this.getCurrChainId());
             this.getIfNode().setCurrChainId(this.getCurrChainId());
             this.getIfNode().execute(slotIndex);
             this.getIfNode().execute(slotIndex);
@@ -37,6 +38,9 @@ public class IfCondition extends Condition {
             //拿到If执行过的结果
             //拿到If执行过的结果
             boolean ifResult = slot.getIfResult(originalClass.getName());
             boolean ifResult = slot.getIfResult(originalClass.getName());
 
 
+            Executable trueCaseExecutableItem = this.getTrueCaseExecutableItem();
+            Executable falseCaseExecutableItem = this.getFalseCaseExecutableItem();
+
             if (ifResult) {
             if (ifResult) {
                 //trueCaseExecutableItem这个不能为空,否则执行什么呢
                 //trueCaseExecutableItem这个不能为空,否则执行什么呢
                 if (ObjectUtil.isNull(trueCaseExecutableItem)) {
                 if (ObjectUtil.isNull(trueCaseExecutableItem)) {
@@ -51,7 +55,7 @@ public class IfCondition extends Condition {
                 }
                 }
 
 
                 //执行trueCaseExecutableItem
                 //执行trueCaseExecutableItem
-                trueCaseExecutableItem.setCurrChainName(this.getCurrChainName());
+                trueCaseExecutableItem.setCurrChainId(this.getCurrChainId());
                 trueCaseExecutableItem.execute(slotIndex);
                 trueCaseExecutableItem.execute(slotIndex);
             } else {
             } else {
                 //falseCaseExecutableItem可以为null,但是不为null时就执行否的情况
                 //falseCaseExecutableItem可以为null,但是不为null时就执行否的情况
@@ -78,22 +82,26 @@ public class IfCondition extends Condition {
     }
     }
 
 
     public Executable getTrueCaseExecutableItem() {
     public Executable getTrueCaseExecutableItem() {
-        return trueCaseExecutableItem;
+        return this.getExecutableOne(ConditionKey.IF_TRUE_CASE_KEY);
     }
     }
 
 
     public void setTrueCaseExecutableItem(Executable trueCaseExecutableItem) {
     public void setTrueCaseExecutableItem(Executable trueCaseExecutableItem) {
-        this.trueCaseExecutableItem = trueCaseExecutableItem;
+        this.addExecutable(ConditionKey.IF_TRUE_CASE_KEY, trueCaseExecutableItem);
     }
     }
 
 
     public Executable getFalseCaseExecutableItem() {
     public Executable getFalseCaseExecutableItem() {
-        return falseCaseExecutableItem;
+        return this.getExecutableOne(ConditionKey.IF_FALSE_CASE_KEY);
     }
     }
 
 
     public void setFalseCaseExecutableItem(Executable falseCaseExecutableItem) {
     public void setFalseCaseExecutableItem(Executable falseCaseExecutableItem) {
-        this.falseCaseExecutableItem = falseCaseExecutableItem;
+        this.addExecutable(ConditionKey.IF_FALSE_CASE_KEY, falseCaseExecutableItem);
+    }
+
+    public void setIfNode(Node ifNode){
+        this.addExecutable(ConditionKey.IF_KEY, ifNode);
     }
     }
 
 
     public Node getIfNode() {
     public Node getIfNode() {
-        return (Node) this.getExecutableList().get(0);
+        return (Node) this.getExecutableOne(ConditionKey.IF_KEY);
     }
     }
 }
 }

+ 15 - 7
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java

@@ -14,28 +14,36 @@ import java.util.Iterator;
 
 
 public class IteratorCondition extends LoopCondition{
 public class IteratorCondition extends LoopCondition{
 
 
-    private Node iteratorNode;
-
     @Override
     @Override
-    public void execute(Integer slotIndex) throws Exception {
+    public void executeCondition(Integer slotIndex) throws Exception {
         Slot slot = DataBus.getSlot(slotIndex);
         Slot slot = DataBus.getSlot(slotIndex);
+        Node iteratorNode = this.getIteratorNode();
+
         if (ObjectUtil.isNull(iteratorNode)){
         if (ObjectUtil.isNull(iteratorNode)){
             String errorInfo = StrUtil.format("[{}]:no iterator-node found", slot.getRequestId());
             String errorInfo = StrUtil.format("[{}]:no iterator-node found", slot.getRequestId());
             throw new NoIteratorNodeException(errorInfo);
             throw new NoIteratorNodeException(errorInfo);
         }
         }
 
 
+        //先去判断isAccess方法,如果isAccess方法都返回false,整个ITERATOR表达式不执行
+        if (!this.getIteratorNode().isAccess(slotIndex)){
+            return;
+        }
+
         //执行Iterator组件
         //执行Iterator组件
         iteratorNode.setCurrChainId(this.getCurrChainId());
         iteratorNode.setCurrChainId(this.getCurrChainId());
         iteratorNode.execute(slotIndex);
         iteratorNode.execute(slotIndex);
 
 
         //这里可能会有spring代理过的bean,所以拿到user原始的class
         //这里可能会有spring代理过的bean,所以拿到user原始的class
-        Class<?> originalForCountClass = LiteFlowProxyUtil.getUserClass(this.iteratorNode.getInstance().getClass());
+        Class<?> originalForCountClass = LiteFlowProxyUtil.getUserClass(iteratorNode.getInstance().getClass());
         //获得迭代器
         //获得迭代器
         Iterator<?> it = slot.getIteratorResult(originalForCountClass.getName());
         Iterator<?> it = slot.getIteratorResult(originalForCountClass.getName());
 
 
         //获得要循环的可执行对象
         //获得要循环的可执行对象
         Executable executableItem = this.getDoExecutor();
         Executable executableItem = this.getDoExecutor();
 
 
+        //获取Break节点
+        Node breakNode = this.getBreakNode();
+
         int index = 0;
         int index = 0;
         while(it.hasNext()){
         while(it.hasNext()){
             Object itObj = it.next();
             Object itObj = it.next();
@@ -53,7 +61,7 @@ public class IteratorCondition extends LoopCondition{
                 setLoopIndex(breakNode, index);
                 setLoopIndex(breakNode, index);
                 setCurrLoopObject(breakNode, itObj);
                 setCurrLoopObject(breakNode, itObj);
                 breakNode.execute(slotIndex);
                 breakNode.execute(slotIndex);
-                Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getInstance().getClass());
+                Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(breakNode.getInstance().getClass());
                 boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
                 boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
                 if (isBreak){
                 if (isBreak){
                     break;
                     break;
@@ -69,10 +77,10 @@ public class IteratorCondition extends LoopCondition{
     }
     }
 
 
     public Node getIteratorNode() {
     public Node getIteratorNode() {
-        return iteratorNode;
+        return (Node) this.getExecutableOne(ConditionKey.ITERATOR_KEY);
     }
     }
 
 
     public void setIteratorNode(Node iteratorNode) {
     public void setIteratorNode(Node iteratorNode) {
-        this.iteratorNode = iteratorNode;
+        this.addExecutable(ConditionKey.ITERATOR_KEY, iteratorNode);
     }
     }
 }
 }

+ 18 - 18
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java

@@ -4,6 +4,10 @@ import com.yomahub.liteflow.flow.element.Chain;
 import com.yomahub.liteflow.flow.element.Executable;
 import com.yomahub.liteflow.flow.element.Executable;
 import com.yomahub.liteflow.flow.element.Node;
 import com.yomahub.liteflow.flow.element.Node;
 
 
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
 /**
 /**
  * 循环Condition的抽象类
  * 循环Condition的抽象类
  * 主要继承对象有ForCondition和WhileCondition
  * 主要继承对象有ForCondition和WhileCondition
@@ -13,25 +17,27 @@ import com.yomahub.liteflow.flow.element.Node;
  */
  */
 public abstract class LoopCondition extends Condition {
 public abstract class LoopCondition extends Condition {
 
 
-    protected Node breakNode;
-
-    public Node getBreakNode() {
-        return breakNode;
+    protected Node getBreakNode() {
+        return (Node) this.getExecutableOne(ConditionKey.BREAK_KEY);
     }
     }
 
 
     public void setBreakNode(Node breakNode) {
     public void setBreakNode(Node breakNode) {
-        this.breakNode = breakNode;
+        this.addExecutable(ConditionKey.BREAK_KEY, breakNode);
+    }
+
+    protected Executable getDoExecutor() {
+        return this.getExecutableOne(ConditionKey.DO_KEY);
+    }
+
+    public void setDoExecutor(Executable executable) {
+        this.addExecutable(ConditionKey.DO_KEY, executable);
     }
     }
 
 
     protected void setLoopIndex(Executable executableItem, int index){
     protected void setLoopIndex(Executable executableItem, int index){
         if (executableItem instanceof Chain){
         if (executableItem instanceof Chain){
             ((Chain)executableItem).getConditionList().forEach(condition -> setLoopIndex(condition, index));
             ((Chain)executableItem).getConditionList().forEach(condition -> setLoopIndex(condition, index));
-        }else if(executableItem instanceof IfCondition){
-            ((Condition)executableItem).getExecutableList().forEach(executable -> setLoopIndex(executable, index));
-            setLoopIndex(((IfCondition)executableItem).getTrueCaseExecutableItem(), index);
-            setLoopIndex(((IfCondition)executableItem).getFalseCaseExecutableItem(), index);
         }else if(executableItem instanceof Condition){
         }else if(executableItem instanceof Condition){
-            ((Condition)executableItem).getExecutableList().forEach(executable -> setLoopIndex(executable, index));
+            ((Condition) executableItem).getExecutableGroup().forEach((key, value) -> value.forEach(executable -> setLoopIndex(executable, index)));
         }else if(executableItem instanceof Node){
         }else if(executableItem instanceof Node){
             ((Node)executableItem).setLoopIndex(index);
             ((Node)executableItem).setLoopIndex(index);
         }
         }
@@ -40,18 +46,12 @@ public abstract class LoopCondition extends Condition {
     protected void setCurrLoopObject(Executable executableItem, Object obj){
     protected void setCurrLoopObject(Executable executableItem, Object obj){
         if (executableItem instanceof Chain){
         if (executableItem instanceof Chain){
             ((Chain)executableItem).getConditionList().forEach(condition -> setCurrLoopObject(condition, obj));
             ((Chain)executableItem).getConditionList().forEach(condition -> setCurrLoopObject(condition, obj));
-        }else if(executableItem instanceof IfCondition){
-            ((Condition)executableItem).getExecutableList().forEach(executable -> setCurrLoopObject(executable, obj));
-            setCurrLoopObject(((IfCondition)executableItem).getTrueCaseExecutableItem(), obj);
-            setCurrLoopObject(((IfCondition)executableItem).getFalseCaseExecutableItem(), obj);
         }else if(executableItem instanceof Condition){
         }else if(executableItem instanceof Condition){
-            ((Condition)executableItem).getExecutableList().forEach(executable -> setCurrLoopObject(executable, obj));
+            ((Condition) executableItem).getExecutableGroup().forEach((key, value) -> value.forEach(executable -> setCurrLoopObject(executable, obj)));
         }else if(executableItem instanceof Node){
         }else if(executableItem instanceof Node){
             ((Node)executableItem).setCurrLoopObject(obj);
             ((Node)executableItem).setCurrLoopObject(obj);
         }
         }
     }
     }
 
 
-    protected Executable getDoExecutor() {
-        return this.getExecutableList().get(0);
-    }
+
 }
 }

+ 1 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/PreCondition.java

@@ -18,7 +18,7 @@ import com.yomahub.liteflow.flow.element.Executable;
 public class PreCondition extends Condition {
 public class PreCondition extends Condition {
 
 
 	@Override
 	@Override
-	public void execute(Integer slotIndex) throws Exception {
+	public void executeCondition(Integer slotIndex) throws Exception {
 		for(Executable executableItem : this.getExecutableList()){
 		for(Executable executableItem : this.getExecutableList()){
 			executableItem.setCurrChainId(this.getCurrChainId());
 			executableItem.setCurrChainId(this.getCurrChainId());
 			executableItem.execute(slotIndex);
 			executableItem.execute(slotIndex);

+ 23 - 20
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/SwitchCondition.java

@@ -23,27 +23,30 @@ import java.util.List;
  * @since 2.8.0
  * @since 2.8.0
  */
  */
 public class SwitchCondition extends Condition{
 public class SwitchCondition extends Condition{
-
-
-    private final List<Executable> targetList = new ArrayList<>();
-
     private final String TAG_PREFIX = "tag";
     private final String TAG_PREFIX = "tag";
     private final String TAG_FLAG = ":";
     private final String TAG_FLAG = ":";
 
 
-    private Executable defaultExecutor;
-
-
     @Override
     @Override
-    public void execute(Integer slotIndex) throws Exception {
+    public void executeCondition(Integer slotIndex) throws Exception {
         if (ListUtil.toList(NodeTypeEnum.SWITCH, NodeTypeEnum.SWITCH_SCRIPT).contains(this.getSwitchNode().getType())){
         if (ListUtil.toList(NodeTypeEnum.SWITCH, NodeTypeEnum.SWITCH_SCRIPT).contains(this.getSwitchNode().getType())){
+            //获取switch node
+            Node switchNode = this.getSwitchNode();
+            //获取target List
+            List<Executable> targetList = this.getTargetList();
+
+            //先去判断isAccess方法,如果isAccess方法都返回false,整个SWITCH表达式不执行
+            if (!switchNode.isAccess(slotIndex)){
+                return;
+            }
+
             //先执行switch节点
             //先执行switch节点
-            this.getSwitchNode().setCurrChainId(this.getCurrChainId());
-            this.getSwitchNode().execute(slotIndex);
+            switchNode.setCurrChainId(this.getCurrChainId());
+            switchNode.execute(slotIndex);
 
 
             //根据switch节点执行出来的结果选择
             //根据switch节点执行出来的结果选择
             Slot slot = DataBus.getSlot(slotIndex);
             Slot slot = DataBus.getSlot(slotIndex);
             //这里可能会有spring代理过的bean,所以拿到user原始的class
             //这里可能会有spring代理过的bean,所以拿到user原始的class
-            Class<?> originalClass = LiteFlowProxyUtil.getUserClass(this.getSwitchNode().getInstance().getClass());
+            Class<?> originalClass = LiteFlowProxyUtil.getUserClass(switchNode.getInstance().getClass());
             String targetId = slot.getSwitchResult(originalClass.getName());
             String targetId = slot.getSwitchResult(originalClass.getName());
 
 
             Executable targetExecutor = null;
             Executable targetExecutor = null;
@@ -70,7 +73,7 @@ public class SwitchCondition extends Condition{
 
 
             if (ObjectUtil.isNull(targetExecutor)) {
             if (ObjectUtil.isNull(targetExecutor)) {
                 //没有匹配到执行节点,则走默认的执行节点
                 //没有匹配到执行节点,则走默认的执行节点
-                targetExecutor = defaultExecutor;
+                targetExecutor = this.getDefaultExecutor();
             }
             }
 
 
             if (ObjectUtil.isNotNull(targetExecutor)) {
             if (ObjectUtil.isNotNull(targetExecutor)) {
@@ -98,26 +101,26 @@ public class SwitchCondition extends Condition{
     }
     }
 
 
     public void addTargetItem(Executable executable){
     public void addTargetItem(Executable executable){
-        this.targetList.add(executable);
+        this.addExecutable(ConditionKey.SWITCH_TARGET_KEY, executable);
     }
     }
 
 
-    public void setSwitchNode(Node switchNode) {
-        this.getExecutableList().add(switchNode);
+    public List<Executable> getTargetList(){
+        return this.getExecutableList(ConditionKey.SWITCH_TARGET_KEY);
     }
     }
 
 
-    public List<Executable> getTargetList(){
-        return targetList;
+    public void setSwitchNode(Node switchNode) {
+        this.addExecutable(ConditionKey.SWITCH_KEY, switchNode);
     }
     }
 
 
     public Node getSwitchNode(){
     public Node getSwitchNode(){
-        return (Node) this.getExecutableList().get(0);
+        return (Node) this.getExecutableOne(ConditionKey.SWITCH_KEY);
     }
     }
 
 
     public Executable getDefaultExecutor() {
     public Executable getDefaultExecutor() {
-        return defaultExecutor;
+        return this.getExecutableOne(ConditionKey.SWITCH_DEFAULT_KEY);
     }
     }
 
 
     public void setDefaultExecutor(Executable defaultExecutor) {
     public void setDefaultExecutor(Executable defaultExecutor) {
-        this.defaultExecutor = defaultExecutor;
+        this.addExecutable(ConditionKey.SWITCH_DEFAULT_KEY, defaultExecutor);
     }
     }
 }
 }

+ 23 - 15
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ThenCondition.java

@@ -12,9 +12,8 @@ import com.yomahub.liteflow.exception.ChainEndException;
 import com.yomahub.liteflow.flow.element.Executable;
 import com.yomahub.liteflow.flow.element.Executable;
 import com.yomahub.liteflow.slot.DataBus;
 import com.yomahub.liteflow.slot.DataBus;
 import com.yomahub.liteflow.slot.Slot;
 import com.yomahub.liteflow.slot.Slot;
-
-import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
+import java.util.stream.Collectors;
 
 
 /**
 /**
  * 串行器
  * 串行器
@@ -22,23 +21,16 @@ import java.util.List;
  */
  */
 public class ThenCondition extends Condition {
 public class ThenCondition extends Condition {
 
 
-	/**
-	 * 前置处理Condition
-	 */
-	private final List<PreCondition> preConditionList = new ArrayList<>();
-
-	/**
-	 * 后置处理Condition
-	 */
-	private final List<FinallyCondition> finallyConditionList = new ArrayList<>();
-
 	@Override
 	@Override
 	public ConditionTypeEnum getConditionType() {
 	public ConditionTypeEnum getConditionType() {
 		return ConditionTypeEnum.TYPE_THEN;
 		return ConditionTypeEnum.TYPE_THEN;
 	}
 	}
 
 
 	@Override
 	@Override
-	public void execute(Integer slotIndex) throws Exception {
+	public void executeCondition(Integer slotIndex) throws Exception {
+		List<PreCondition> preConditionList = this.getPreConditionList();
+		List<FinallyCondition> finallyConditionList = this.getFinallyConditionList();
+
 		try{
 		try{
 			for (PreCondition preCondition : preConditionList){
 			for (PreCondition preCondition : preConditionList){
 				preCondition.setCurrChainId(this.getCurrChainId());
 				preCondition.setCurrChainId(this.getCurrChainId());
@@ -74,11 +66,27 @@ public class ThenCondition extends Condition {
 	@Override
 	@Override
 	public void addExecutable(Executable executable) {
 	public void addExecutable(Executable executable) {
 		if (executable instanceof PreCondition){
 		if (executable instanceof PreCondition){
-			preConditionList.add((PreCondition) executable);
+			this.addPreCondition((PreCondition) executable);
 		}else if (executable instanceof FinallyCondition){
 		}else if (executable instanceof FinallyCondition){
-			finallyConditionList.add((FinallyCondition) executable);
+			this.addFinallyCondition((FinallyCondition) executable);
 		}else{
 		}else{
 			super.addExecutable(executable);
 			super.addExecutable(executable);
 		}
 		}
 	}
 	}
+
+	public List<PreCondition> getPreConditionList() {
+		return this.getExecutableList(ConditionKey.PRE_KEY).stream().map(executable -> (PreCondition) executable).collect(Collectors.toList());
+	}
+
+	public void addPreCondition(PreCondition preCondition){
+		this.addExecutable(ConditionKey.PRE_KEY, preCondition);
+	}
+
+	public List<FinallyCondition> getFinallyConditionList() {
+		return this.getExecutableList(ConditionKey.FINALLY_KEY).stream().map(executable -> (FinallyCondition) executable).collect(Collectors.toList());
+	}
+
+	public void addFinallyCondition(FinallyCondition finallyCondition){
+		this.addExecutable(ConditionKey.FINALLY_KEY, finallyCondition);
+	}
 }
 }

+ 1 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java

@@ -51,7 +51,7 @@ public class WhenCondition extends Condition {
 
 
 
 
 	@Override
 	@Override
-	public void execute(Integer slotIndex) throws Exception {
+	public void executeCondition(Integer slotIndex) throws Exception {
 		executeAsyncCondition(slotIndex);
 		executeAsyncCondition(slotIndex);
 	}
 	}
 
 

+ 15 - 7
liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java

@@ -18,19 +18,26 @@ import com.yomahub.liteflow.util.LiteFlowProxyUtil;
  */
  */
 public class WhileCondition extends LoopCondition{
 public class WhileCondition extends LoopCondition{
 
 
-    private Node whileNode;
-
     @Override
     @Override
-    public void execute(Integer slotIndex) throws Exception {
+    public void executeCondition(Integer slotIndex) throws Exception {
         Slot slot = DataBus.getSlot(slotIndex);
         Slot slot = DataBus.getSlot(slotIndex);
+        Node whileNode = this.getWhileNode();
         if (ObjectUtil.isNull(whileNode)){
         if (ObjectUtil.isNull(whileNode)){
             String errorInfo = StrUtil.format("[{}]:no while-node found", slot.getRequestId());
             String errorInfo = StrUtil.format("[{}]:no while-node found", slot.getRequestId());
             throw new NoWhileNodeException(errorInfo);
             throw new NoWhileNodeException(errorInfo);
         }
         }
 
 
+        //先去判断isAccess方法,如果isAccess方法都返回false,整个WHILE表达式不执行
+        if (!this.getWhileNode().isAccess(slotIndex)){
+            return;
+        }
+
         //获得要循环的可执行对象
         //获得要循环的可执行对象
         Executable executableItem = this.getDoExecutor();
         Executable executableItem = this.getDoExecutor();
 
 
+        //获取Break节点
+        Node breakNode = this.getBreakNode();
+
         //循环执行
         //循环执行
         int index = 0;
         int index = 0;
         while(getWhileResult(slotIndex)){
         while(getWhileResult(slotIndex)){
@@ -42,7 +49,7 @@ public class WhileCondition extends LoopCondition{
                 breakNode.setCurrChainId(this.getCurrChainId());
                 breakNode.setCurrChainId(this.getCurrChainId());
                 setLoopIndex(breakNode, index);
                 setLoopIndex(breakNode, index);
                 breakNode.execute(slotIndex);
                 breakNode.execute(slotIndex);
-                Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getInstance().getClass());
+                Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(breakNode.getInstance().getClass());
                 boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
                 boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
                 if (isBreak){
                 if (isBreak){
                     break;
                     break;
@@ -54,10 +61,11 @@ public class WhileCondition extends LoopCondition{
 
 
     private boolean getWhileResult(Integer slotIndex) throws Exception{
     private boolean getWhileResult(Integer slotIndex) throws Exception{
         Slot slot = DataBus.getSlot(slotIndex);
         Slot slot = DataBus.getSlot(slotIndex);
+        Node whileNode = this.getWhileNode();
         //执行while组件
         //执行while组件
         whileNode.setCurrChainId(this.getCurrChainId());
         whileNode.setCurrChainId(this.getCurrChainId());
         whileNode.execute(slotIndex);
         whileNode.execute(slotIndex);
-        Class<?> originalWhileClass = LiteFlowProxyUtil.getUserClass(this.whileNode.getInstance().getClass());
+        Class<?> originalWhileClass = LiteFlowProxyUtil.getUserClass(whileNode.getInstance().getClass());
         return slot.getWhileResult(originalWhileClass.getName());
         return slot.getWhileResult(originalWhileClass.getName());
     }
     }
 
 
@@ -67,10 +75,10 @@ public class WhileCondition extends LoopCondition{
     }
     }
 
 
     public Node getWhileNode() {
     public Node getWhileNode() {
-        return whileNode;
+        return (Node) this.getExecutableOne(ConditionKey.WHILE_KEY);
     }
     }
 
 
     public void setWhileNode(Node whileNode) {
     public void setWhileNode(Node whileNode) {
-        this.whileNode = whileNode;
+        this.addExecutable(ConditionKey.WHILE_KEY, whileNode);
     }
     }
 }
 }

+ 4 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/monitor/MonitorBus.java

@@ -100,4 +100,8 @@ public class MonitorBus {
 	public void closeScheduler(){
 	public void closeScheduler(){
 		this.printLogScheduler.shutdown();
 		this.printLogScheduler.shutdown();
 	}
 	}
+
+	public ConcurrentHashMap<String, BoundedPriorityBlockingQueue<CompStatistics>> getStatisticsMap() {
+		return statisticsMap;
+	}
 }
 }

+ 94 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/monitor/MonitorFile.java

@@ -0,0 +1,94 @@
+package com.yomahub.liteflow.monitor;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.watch.SimpleWatcher;
+import cn.hutool.core.io.watch.WatchMonitor;
+import cn.hutool.core.io.watch.watchers.DelayWatcher;
+import cn.hutool.core.lang.Singleton;
+import com.yomahub.liteflow.core.FlowExecutorHolder;
+import org.apache.commons.io.filefilter.FileFilterUtils;
+import org.apache.commons.io.filefilter.HiddenFileFilter;
+import org.apache.commons.io.filefilter.IOFileFilter;
+import org.apache.commons.io.monitor.FileAlterationListener;
+import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
+import org.apache.commons.io.monitor.FileAlterationMonitor;
+import org.apache.commons.io.monitor.FileAlterationObserver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.WatchEvent;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * 规则文件监听器
+ *
+ * @author tangkc
+ */
+public class MonitorFile {
+
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+    private final Set<String> PATH_SET = new HashSet<>();
+
+    public static MonitorFile getInstance() {
+        return Singleton.get(MonitorFile.class);
+    }
+
+    /**
+     * 添加监听文件路径
+     *
+     * @param path 文件路径
+     */
+    public void addMonitorFilePath(String path) {
+        if (FileUtil.isFile(path)){
+            String parentFolder = FileUtil.getParent(path, 1);
+            PATH_SET.add(parentFolder);
+        }else{
+            PATH_SET.add(path);
+        }
+    }
+
+    /**
+     * 添加监听文件路径
+     *
+     * @param filePaths 文件路径
+     */
+    public void addMonitorFilePaths(List<String> filePaths) {
+        filePaths.forEach(this::addMonitorFilePath);
+    }
+
+    /**
+     * 创建文件监听
+     */
+    public void create() throws Exception{
+        for (String path : PATH_SET) {
+            long interval = TimeUnit.MILLISECONDS.toMillis(2);
+            //不使用过滤器
+            FileAlterationObserver observer = new FileAlterationObserver(new File(path));
+            observer.addListener(new FileAlterationListenerAdaptor() {
+                @Override
+                public void onFileChange(File file) {
+                    logger.info("file modify,filePath={}", file.getAbsolutePath());
+                    FlowExecutorHolder.loadInstance().reloadRule();
+                }
+
+                @Override
+                public void onFileDelete(File file) {
+                    logger.info("file delete,filePath={}", file.getAbsolutePath());
+                    FlowExecutorHolder.loadInstance().reloadRule();
+                }
+            });
+            //创建文件变化监听器
+            FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);
+            // 开始监控
+            monitor.start();
+        }
+    }
+}

+ 1 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalJsonFlowELParser.java

@@ -6,6 +6,7 @@ import java.util.List;
 
 
 /**
 /**
  * 基于本地的json方式EL表达式解析器
  * 基于本地的json方式EL表达式解析器
+ *
  * @author Bryan.Zhang
  * @author Bryan.Zhang
  * @since 2.8.0
  * @since 2.8.0
  */
  */

+ 6 - 2
liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java

@@ -44,6 +44,7 @@ public class ParserHelper {
 		String script = nodePropBean.getScript();
 		String script = nodePropBean.getScript();
 		String type = nodePropBean.getType();
 		String type = nodePropBean.getType();
 		String file = nodePropBean.getFile();
 		String file = nodePropBean.getFile();
+		String language = nodePropBean.getLanguage();
 
 
 		//clazz有值的,基本都不是脚本节点
 		//clazz有值的,基本都不是脚本节点
 		//脚本节点,都必须配置type
 		//脚本节点,都必须配置type
@@ -80,6 +81,7 @@ public class ParserHelper {
 				.setType(nodeTypeEnum)
 				.setType(nodeTypeEnum)
 				.setScript(script)
 				.setScript(script)
 				.setFile(file)
 				.setFile(file)
+				.setLanguage(language)
 				.build();
 				.build();
 	}
 	}
 
 
@@ -98,7 +100,7 @@ public class ParserHelper {
 			// 当存在<nodes>节点定义时,解析node节点
 			// 当存在<nodes>节点定义时,解析node节点
 			if (ObjectUtil.isNotNull(nodesElement)) {
 			if (ObjectUtil.isNotNull(nodesElement)) {
 				List<Element> nodeList = nodesElement.elements(NODE);
 				List<Element> nodeList = nodesElement.elements(NODE);
-				String id, name, clazz, type, script, file;
+				String id, name, clazz, type, script, file, language;
 				for (Element e : nodeList) {
 				for (Element e : nodeList) {
 					id = e.attributeValue(ID);
 					id = e.attributeValue(ID);
 					name = e.attributeValue(NAME);
 					name = e.attributeValue(NAME);
@@ -106,6 +108,7 @@ public class ParserHelper {
 					type = e.attributeValue(TYPE);
 					type = e.attributeValue(TYPE);
 					script = e.getText();
 					script = e.getText();
 					file = e.attributeValue(FILE);
 					file = e.attributeValue(FILE);
+					language = e.attributeValue(LANGUAGE);
 
 
 					// 构建 node
 					// 构建 node
 					NodePropBean nodePropBean = new NodePropBean()
 					NodePropBean nodePropBean = new NodePropBean()
@@ -114,7 +117,8 @@ public class ParserHelper {
 							.setClazz(clazz)
 							.setClazz(clazz)
 							.setScript(script)
 							.setScript(script)
 							.setType(type)
 							.setType(type)
-							.setFile(file);
+							.setFile(file)
+							.setLanguage(language);
 
 
 					ParserHelper.buildNode(nodePropBean);
 					ParserHelper.buildNode(nodePropBean);
 				}
 				}

+ 11 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java

@@ -94,6 +94,17 @@ public class LiteflowConfig {
     //替补组件class路径
     //替补组件class路径
     private String substituteCmpClass;
     private String substituteCmpClass;
 
 
+    // 规则文件/脚本文件变更监听
+    private Boolean enableMonitorFile = Boolean.FALSE;
+
+    public Boolean getEnableMonitorFile() {
+        return enableMonitorFile;
+    }
+
+    public void setEnableMonitorFile(Boolean enableMonitorFile) {
+        this.enableMonitorFile = enableMonitorFile;
+    }
+
     public Boolean getEnable() {
     public Boolean getEnable() {
         if (ObjectUtil.isNull(enable)) {
         if (ObjectUtil.isNull(enable)) {
             return Boolean.TRUE;
             return Boolean.TRUE;

+ 4 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/script/ScriptExecutor.java

@@ -1,5 +1,7 @@
 package com.yomahub.liteflow.script;
 package com.yomahub.liteflow.script;
 
 
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
+
 /**
 /**
  * 脚本执行器接口
  * 脚本执行器接口
  * @author Bryan.Zhang
  * @author Bryan.Zhang
@@ -14,4 +16,6 @@ public interface ScriptExecutor {
     Object execute(ScriptExecuteWrap wrap) throws Exception;
     Object execute(ScriptExecuteWrap wrap) throws Exception;
 
 
     void cleanCache();
     void cleanCache();
+
+    ScriptTypeEnum scriptType();
 }
 }

+ 43 - 9
liteflow-core/src/main/java/com/yomahub/liteflow/script/ScriptExecutorFactory.java

@@ -1,9 +1,15 @@
 package com.yomahub.liteflow.script;
 package com.yomahub.liteflow.script;
 
 
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
 import com.yomahub.liteflow.script.exception.ScriptSpiException;
 import com.yomahub.liteflow.script.exception.ScriptSpiException;
 
 
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
 import java.util.ServiceLoader;
 import java.util.ServiceLoader;
+import java.util.function.Consumer;
 
 
 /**
 /**
  * 脚本执行器工厂类
  * 脚本执行器工厂类
@@ -14,7 +20,9 @@ public class ScriptExecutorFactory {
 
 
     private static ScriptExecutorFactory scriptExecutorFactory;
     private static ScriptExecutorFactory scriptExecutorFactory;
 
 
-    private ScriptExecutor scriptExecutor;
+    private final Map<String,ScriptExecutor> scriptExecutorMap = new HashMap<>();
+
+    private final String NONE_LANGUAGE = "none";
 
 
     public static ScriptExecutorFactory loadInstance(){
     public static ScriptExecutorFactory loadInstance(){
         if (ObjectUtil.isNull(scriptExecutorFactory)){
         if (ObjectUtil.isNull(scriptExecutorFactory)){
@@ -23,17 +31,43 @@ public class ScriptExecutorFactory {
         return scriptExecutorFactory;
         return scriptExecutorFactory;
     }
     }
 
 
-    public ScriptExecutor getScriptExecutor(){
-        if (ObjectUtil.isNull(scriptExecutor)){
+    public ScriptExecutor getScriptExecutor(String language){
+        if (StrUtil.isBlank(language)){
+            language = NONE_LANGUAGE;
+        }
+
+
+        if (!scriptExecutorMap.containsKey(language)){
             ServiceLoader<ScriptExecutor> loader = ServiceLoader.load(ScriptExecutor.class);
             ServiceLoader<ScriptExecutor> loader = ServiceLoader.load(ScriptExecutor.class);
 
 
-            if (loader.iterator().hasNext()){
-                scriptExecutor = loader.iterator().next().init();
-                return scriptExecutor;
-            }else{
-                throw new ScriptSpiException("script spi component failed to load");
+            ScriptExecutor scriptExecutor;
+            Iterator<ScriptExecutor> it = loader.iterator();
+            while(it.hasNext()){
+                scriptExecutor = it.next().init();
+                if (language.equals(NONE_LANGUAGE)){
+                    scriptExecutorMap.put(language, scriptExecutor);
+                    break;
+                }else{
+                    ScriptTypeEnum scriptType = ScriptTypeEnum.getEnumByDisplayName(language);
+                    if (ObjectUtil.isNull(scriptType)){
+                        throw new ScriptSpiException("script language config error");
+                    }
+                    if (scriptType.equals(scriptExecutor.scriptType())){
+                        scriptExecutorMap.put(language, scriptExecutor);
+                        break;
+                    }
+                }
             }
             }
         }
         }
-        return scriptExecutor;
+
+        if (scriptExecutorMap.containsKey(language)){
+            return scriptExecutorMap.get(language);
+        }else{
+            throw new ScriptSpiException("script spi component failed to load");
+        }
+    }
+
+    public void cleanScriptCache(){
+        this.scriptExecutorMap.forEach((key, value) -> value.cleanCache());
     }
     }
 }
 }

+ 11 - 4
liteflow-core/src/main/java/com/yomahub/liteflow/script/jsr223/JSR223ScriptExecutor.java

@@ -3,6 +3,8 @@ package com.yomahub.liteflow.script.jsr223;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.annotation.util.AnnoUtil;
+import com.yomahub.liteflow.context.ContextBean;
 import com.yomahub.liteflow.exception.LiteFlowException;
 import com.yomahub.liteflow.exception.LiteFlowException;
 import com.yomahub.liteflow.script.ScriptBeanManager;
 import com.yomahub.liteflow.script.ScriptBeanManager;
 import com.yomahub.liteflow.script.ScriptExecuteWrap;
 import com.yomahub.liteflow.script.ScriptExecuteWrap;
@@ -16,6 +18,7 @@ import org.slf4j.LoggerFactory;
 
 
 import javax.script.*;
 import javax.script.*;
 import java.util.Map;
 import java.util.Map;
+import java.util.Optional;
 
 
 /**
 /**
  * JSR223 script engine的统一实现抽象类
  * JSR223 script engine的统一实现抽象类
@@ -33,12 +36,10 @@ public abstract class JSR223ScriptExecutor implements ScriptExecutor {
     @Override
     @Override
     public ScriptExecutor init() {
     public ScriptExecutor init() {
         ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
         ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
-        scriptEngine = scriptEngineManager.getEngineByName(scriptEngineName());
+        scriptEngine = scriptEngineManager.getEngineByName(this.scriptType().getEngineName());
         return this;
         return this;
     }
     }
 
 
-    protected abstract String scriptEngineName();
-
     protected String convertScript(String script){
     protected String convertScript(String script){
         return script;
         return script;
     }
     }
@@ -71,7 +72,13 @@ public abstract class JSR223ScriptExecutor implements ScriptExecutor {
             //比如你的自定义上下文为AbcContext,那么key就为:abcContext
             //比如你的自定义上下文为AbcContext,那么key就为:abcContext
             //这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
             //这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
             DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
             DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
-                String key = StrUtil.lowerFirst(o.getClass().getSimpleName());
+                ContextBean contextBean = AnnoUtil.getAnnotation(o.getClass(),ContextBean.class);
+                String key;
+                if(contextBean !=null && contextBean.value().trim().length()>0){
+                    key = contextBean.value();
+                }else{
+                    key = StrUtil.lowerFirst(o.getClass().getSimpleName());
+                }
                 bindings.put(key, o);
                 bindings.put(key, o);
             });
             });
 
 

+ 4 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/slot/Slot.java

@@ -339,6 +339,10 @@ public class Slot{
 		putMetaDataMap(EXCEPTION, e);
 		putMetaDataMap(EXCEPTION, e);
 	}
 	}
 
 
+	public void removeException(){
+		metaDataMap.remove(EXCEPTION);
+	}
+
 	public Exception getSubException(String chainId) {
 	public Exception getSubException(String chainId) {
 		return (Exception) this.metaDataMap.get(SUB_EXCEPTION_PREFIX + chainId);
 		return (Exception) this.metaDataMap.get(SUB_EXCEPTION_PREFIX + chainId);
 	}
 	}

+ 17 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/spi/PathContentParser.java

@@ -2,7 +2,23 @@ package com.yomahub.liteflow.spi;
 
 
 import java.util.List;
 import java.util.List;
 
 
-public interface PathContentParser extends SpiPriority{
+public interface PathContentParser extends SpiPriority {
 
 
+    /**
+     * 解析路径下的文件内容
+     *
+     * @param pathList 文件路径(支持 classpath 路径和 file 绝对路径,spring 环境支持 PathMatchingResourcePatternResolver 规则)
+     * @return 返回文件内容
+     * @throws Exception ex
+     */
     List<String> parseContent(List<String> pathList) throws Exception;
     List<String> parseContent(List<String> pathList) throws Exception;
+
+    /**
+     * 获取文件路径的绝对路径
+     *
+     * @param pathList 文件路径(支持 classpath 路径和 file 绝对路径,spring 环境支持 PathMatchingResourcePatternResolver 规则)
+     * @return 返回文件绝对路径
+     * @throws Exception ex
+     */
+    List<String> getFileAbsolutePath(List<String> pathList) throws Exception;
 }
 }

+ 34 - 4
liteflow-core/src/main/java/com/yomahub/liteflow/spi/local/LocalPathContentParser.java

@@ -2,7 +2,10 @@ package com.yomahub.liteflow.spi.local;
 
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ClassPathResource;
+import cn.hutool.core.io.resource.FileResource;
 import cn.hutool.core.io.resource.ResourceUtil;
 import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.util.ClassLoaderUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
 import com.yomahub.liteflow.exception.ConfigErrorException;
 import com.yomahub.liteflow.exception.ConfigErrorException;
 import com.yomahub.liteflow.spi.PathContentParser;
 import com.yomahub.liteflow.spi.PathContentParser;
@@ -18,14 +21,14 @@ public class LocalPathContentParser implements PathContentParser {
 
 
     @Override
     @Override
     public List<String> parseContent(List<String> pathList) throws Exception {
     public List<String> parseContent(List<String> pathList) throws Exception {
-        if(CollectionUtil.isEmpty(pathList)){
+        if (CollectionUtil.isEmpty(pathList)) {
             throw new ConfigErrorException("rule source must not be null");
             throw new ConfigErrorException("rule source must not be null");
         }
         }
 
 
         List<String> contentList = new ArrayList<>();
         List<String> contentList = new ArrayList<>();
 
 
-        for(String path : pathList){
-            if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)){
+        for (String path : pathList) {
+            if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)) {
                 path = FILE_URL_PREFIX + path;
                 path = FILE_URL_PREFIX + path;
             } else {
             } else {
                 if (!path.startsWith(CLASSPATH_URL_PREFIX)) {
                 if (!path.startsWith(CLASSPATH_URL_PREFIX)) {
@@ -33,7 +36,7 @@ public class LocalPathContentParser implements PathContentParser {
                 }
                 }
             }
             }
             String content = ResourceUtil.readUtf8Str(path);
             String content = ResourceUtil.readUtf8Str(path);
-            if (StrUtil.isNotBlank(content)){
+            if (StrUtil.isNotBlank(content)) {
                 contentList.add(content);
                 contentList.add(content);
             }
             }
         }
         }
@@ -41,6 +44,33 @@ public class LocalPathContentParser implements PathContentParser {
         return contentList;
         return contentList;
     }
     }
 
 
+    @Override
+    public List<String> getFileAbsolutePath(List<String> pathList) throws Exception {
+        if (CollectionUtil.isEmpty(pathList)) {
+            throw new ConfigErrorException("rule source must not be null");
+        }
+
+        List<String> result = new ArrayList<>();
+
+        for (String path : pathList) {
+             if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)) {
+                path = FILE_URL_PREFIX + path;
+                result.add(new FileResource(path).getFile().getAbsolutePath());
+            } else {
+                if (!path.startsWith(CLASSPATH_URL_PREFIX)) {
+                    path = CLASSPATH_URL_PREFIX + path;
+
+                    // 这里会有自定义解析器
+                    if(ClassLoaderUtil.isPresent(path)){
+                        result.add(new ClassPathResource(path).getAbsolutePath());
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+
     @Override
     @Override
     public int priority() {
     public int priority() {
         return 2;
         return 2;

+ 4 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/util/LOGOPrinter.java

@@ -26,8 +26,11 @@ public class LOGOPrinter {
 		str.append("		| |___ | |  | | | |__|_____|  _| | |__| |_| |\\ V  V /  \n");
 		str.append("		| |___ | |  | | | |__|_____|  _| | |__| |_| |\\ V  V /  \n");
 		str.append("		|_____|___| |_| |_____|    |_|   |_____\\___/  \\_/\\_/   \n\n");
 		str.append("		|_____|___| |_| |_____|    |_|   |_____\\___/  \\_/\\_/   \n\n");
 		str.append("		Version: " + VERSION_NO + "\n");
 		str.append("		Version: " + VERSION_NO + "\n");
-		str.append("		轻量且强大的规则引擎框架。\n");
+		str.append("		新一代轻量且强大的规则引擎编排框架。\n");
+		str.append("		基于开源社区文化,社区驱动型开源框架。\n");
 		str.append("		Small but powerful rules engine.\n");
 		str.append("		Small but powerful rules engine.\n");
+		str.append("		官网地址:https://liteflow.yomahub.com/\n");
+		str.append("		wechat:bryan_31\n");
 		str.append("================================================================================================\n");
 		str.append("================================================================================================\n");
 		LOG.info(str.toString());
 		LOG.info(str.toString());
 	}
 	}

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

@@ -2,9 +2,11 @@ package com.yomahub.liteflow.parser.sql.util;
 
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.XmlUtil;
 import com.yomahub.liteflow.enums.NodeTypeEnum;
 import com.yomahub.liteflow.enums.NodeTypeEnum;
 import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
 import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
 import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
 import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
+
 import java.sql.Connection;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.PreparedStatement;
@@ -22,250 +24,250 @@ import java.util.Objects;
  */
  */
 public class JDBCHelper {
 public class JDBCHelper {
 
 
-	private static final String SQL_PATTERN = "SELECT {},{} FROM {} WHERE {}=?";
-
-	private static final String SCRIPT_SQL_CHECK_PATTERN = "SELECT 1 FROM {} WHERE {}=?";
-
-	private static final String SCRIPT_SQL_PATTERN = "SELECT {},{},{},{} FROM {} WHERE {}=?";
-
-	private static final String CHAIN_XML_PATTERN = "<chain name=\"{}\">{}</chain>";
-	private static final String NODE_XML_PATTERN = "<nodes>{}</nodes>";
-
-	private static final String NODE_ITEM_XML_PATTERN = "<node id=\"{}\" name=\"{}\" type=\"{}\"><![CDATA[{}]]></node>";
-	private static final String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}{}</flow>";
-	private static final Integer FETCH_SIZE_MAX = 1000;
-
-	private SQLParserVO sqlParserVO;
-
-	private static JDBCHelper INSTANCE;
-
-	/**
-	 * 初始化 INSTANCE
-	 */
-	public static void init(SQLParserVO sqlParserVO) {
-		try {
-			INSTANCE = new JDBCHelper();
-			Class.forName(sqlParserVO.getDriverClassName());
-			INSTANCE.setSqlParserVO(sqlParserVO);
-		} catch (ClassNotFoundException e) {
-			throw new ELSQLException(e.getMessage());
-		}
-	}
-
-	/**
-	 * 获取 INSTANCE
-	 */
-	public static JDBCHelper getInstance() {
-		return INSTANCE;
-	}
-
-	/**
-	 * 获取链接
-	 */
-	public Connection getConn() {
-		Connection connection;
-		try {
-			connection = DriverManager.getConnection(sqlParserVO.getUrl(), sqlParserVO.getUsername(), sqlParserVO.getPassword());
-		} catch (SQLException e) {
-			throw new ELSQLException(e.getMessage());
-		}
-		return connection;
-	}
-
-	/**
-	 * 获取 ElData 数据内容
-	 */
-	public String getContent() {
-		Connection conn = null;
-		PreparedStatement stmt = null;
-		ResultSet rs = null;
-
-		String chainTableName = sqlParserVO.getChainTableName();
-		String elDataField = sqlParserVO.getElDataField();
-		String chainNameField = sqlParserVO.getChainNameField();
-		String chainApplicationNameField = sqlParserVO.getChainApplicationNameField();
-		String applicationName = sqlParserVO.getApplicationName();
-
-		if(StrUtil.isBlank(chainTableName)){
-			throw new ELSQLException("You did not define the chainTableName property");
-		}
-
-		if(StrUtil.isBlank(applicationName) || StrUtil.isBlank(chainApplicationNameField)){
-			throw new ELSQLException("You did not define the applicationName or chainApplicationNameField property");
-		}
-
-		String sqlCmd = StrUtil.format(SQL_PATTERN, chainNameField, elDataField, chainTableName, chainApplicationNameField);
-
-		List<String> result = new ArrayList<>();
-		try {
-			conn = getConn();
-			stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
-			// 设置游标拉取数量
-			stmt.setFetchSize(FETCH_SIZE_MAX);
-			stmt.setString(1, applicationName);
-			rs = stmt.executeQuery();
-
-			while (rs.next()) {
-				String elData = getStringFromResultSet(rs, elDataField);
-				String chainName = getStringFromResultSet(rs, chainNameField);
-
-				result.add(StrUtil.format(CHAIN_XML_PATTERN, chainName, elData));
-			}
-		} catch (Exception e) {
-			throw new ELSQLException(e.getMessage());
-		} finally {
-			// 关闭连接
-			close(conn, stmt, rs);
-		}
-
-		String chainsContent = CollUtil.join(result, StrUtil.EMPTY);
-
-		String nodesContent;
-		if (hasScriptData()){
-			nodesContent = getScriptNodes();
-		}else{
-			nodesContent = StrUtil.EMPTY;
-		}
-
-		return StrUtil.format(XML_PATTERN, nodesContent, chainsContent);
-	}
-
-	public String getScriptNodes() {
-		List<String> result = new ArrayList<>();
-		Connection conn = null;
-		PreparedStatement stmt = null;
-		ResultSet rs = null;
-
-		String scriptTableName = sqlParserVO.getScriptTableName();
-		String scriptIdField = sqlParserVO.getScriptIdField();
-		String scriptDataField = sqlParserVO.getScriptDataField();
-		String scriptNameField = sqlParserVO.getScriptNameField();
-		String scriptTypeField = sqlParserVO.getScriptTypeField();
-		String scriptApplicationNameField = sqlParserVO.getScriptApplicationNameField();
-		String applicationName = sqlParserVO.getApplicationName();
-
-		if(StrUtil.isBlank(applicationName) || StrUtil.isBlank(scriptApplicationNameField)){
-			throw new ELSQLException("You did not define the applicationName or scriptApplicationNameField property");
-		}
-
-		String sqlCmd = StrUtil.format(
-				SCRIPT_SQL_PATTERN,
-				scriptIdField,
-				scriptDataField,
-				scriptNameField,
-				scriptTypeField,
-				scriptTableName,
-				scriptApplicationNameField
-		);
-		try {
-			conn = getConn();
-			stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
-			// 设置游标拉取数量
-			stmt.setFetchSize(FETCH_SIZE_MAX);
-			stmt.setString(1, applicationName);
-			rs = stmt.executeQuery();
-
-			while (rs.next()) {
-				String id = getStringFromResultSet(rs, scriptIdField);
-				String data = getStringFromResultSet(rs, scriptDataField);
-				String name = getStringFromResultSet(rs, scriptNameField);
-				String type = getStringFromResultSet(rs, scriptTypeField);
-
-				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));
-				}
-
-				result.add(StrUtil.format(NODE_ITEM_XML_PATTERN, id, name, type, data));
-			}
-		} catch (Exception e) {
-			throw new ELSQLException(e.getMessage());
-		} finally {
-			// 关闭连接
-			close(conn, stmt, rs);
-		}
-		return StrUtil.format(NODE_XML_PATTERN, CollUtil.join(result, StrUtil.EMPTY));
-	}
-
-	/**
-	 * 关闭连接
-	 *
-	 * @param conn conn
-	 * @param stmt stmt
-	 * @param rs   rs
-	 */
-	private void close(Connection conn, PreparedStatement stmt, ResultSet rs) {
-		// 关闭连接
-		if (conn != null) {
-			try {
-				conn.close();
-			} catch (SQLException e) {
-				throw new ELSQLException(e.getMessage());
-			}
-		}
-		// 关闭 statement
-		if (stmt != null) {
-			try {
-				stmt.close();
-			} catch (SQLException e) {
-				throw new ELSQLException(e.getMessage());
-			}
-		}
-		//关闭结果集
-		if (rs != null) {
-			try {
-				rs.close();
-			} catch (SQLException e) {
-				throw new ELSQLException(e.getMessage());
-			}
-		}
-	}
-
-	private boolean hasScriptData(){
-		if (StrUtil.isBlank(sqlParserVO.getScriptTableName())){
-			return false;
-		}
-
-		Connection conn = null;
-		PreparedStatement stmt = null;
-		ResultSet rs = null;
-		String sqlCmd = StrUtil.format(SCRIPT_SQL_CHECK_PATTERN,
-				sqlParserVO.getScriptTableName(),
-				sqlParserVO.getScriptApplicationNameField());
-		try {
-			conn = getConn();
-			stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
-			stmt.setFetchSize(1);
-			stmt.setString(1, sqlParserVO.getApplicationName());
-			rs = stmt.executeQuery();
-			return rs.next();
-		} catch (Exception e) {
-			return false;
-		} finally {
-			// 关闭连接
-			close(conn, stmt, rs);
-		}
-	}
-
-
-	//#region get set method
-	private String getStringFromResultSet(ResultSet rs, String field) throws SQLException {
-		String data = rs.getString(field);
-		if (StrUtil.isBlank(data)) {
-			throw new ELSQLException(StrUtil.format("exist {} field value is empty", field));
-		}
-		return data;
-	}
-
-	private SQLParserVO getSqlParserVO() {
-		return sqlParserVO;
-	}
-
-	private void setSqlParserVO(SQLParserVO sqlParserVO) {
-		this.sqlParserVO = sqlParserVO;
-	}
+    private static final String SQL_PATTERN = "SELECT {},{} FROM {} WHERE {}=?";
+
+    private static final String SCRIPT_SQL_CHECK_PATTERN = "SELECT 1 FROM {} WHERE {}=?";
+
+    private static final String SCRIPT_SQL_PATTERN = "SELECT {},{},{},{} FROM {} WHERE {}=?";
+
+    private static final String CHAIN_XML_PATTERN = "<chain name=\"{}\">{}</chain>";
+    private static final String NODE_XML_PATTERN = "<nodes>{}</nodes>";
+
+    private static final String NODE_ITEM_XML_PATTERN = "<node id=\"{}\" name=\"{}\" type=\"{}\"><![CDATA[{}]]></node>";
+    private static final String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}{}</flow>";
+    private static final Integer FETCH_SIZE_MAX = 1000;
+
+    private SQLParserVO sqlParserVO;
+
+    private static JDBCHelper INSTANCE;
+
+    /**
+     * 初始化 INSTANCE
+     */
+    public static void init(SQLParserVO sqlParserVO) {
+        try {
+            INSTANCE = new JDBCHelper();
+            Class.forName(sqlParserVO.getDriverClassName());
+            INSTANCE.setSqlParserVO(sqlParserVO);
+        } catch (ClassNotFoundException e) {
+            throw new ELSQLException(e.getMessage());
+        }
+    }
+
+    /**
+     * 获取 INSTANCE
+     */
+    public static JDBCHelper getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * 获取链接
+     */
+    public Connection getConn() {
+        Connection connection;
+        try {
+            connection = DriverManager.getConnection(sqlParserVO.getUrl(), sqlParserVO.getUsername(), sqlParserVO.getPassword());
+        } catch (SQLException e) {
+            throw new ELSQLException(e.getMessage());
+        }
+        return connection;
+    }
+
+    /**
+     * 获取 ElData 数据内容
+     */
+    public String getContent() {
+        Connection conn = null;
+        PreparedStatement stmt = null;
+        ResultSet rs = null;
+
+        String chainTableName = sqlParserVO.getChainTableName();
+        String elDataField = sqlParserVO.getElDataField();
+        String chainNameField = sqlParserVO.getChainNameField();
+        String chainApplicationNameField = sqlParserVO.getChainApplicationNameField();
+        String applicationName = sqlParserVO.getApplicationName();
+
+        if (StrUtil.isBlank(chainTableName)) {
+            throw new ELSQLException("You did not define the chainTableName property");
+        }
+
+        if (StrUtil.isBlank(applicationName) || StrUtil.isBlank(chainApplicationNameField)) {
+            throw new ELSQLException("You did not define the applicationName or chainApplicationNameField property");
+        }
+
+        String sqlCmd = StrUtil.format(SQL_PATTERN, chainNameField, elDataField, chainTableName, chainApplicationNameField);
+
+        List<String> result = new ArrayList<>();
+        try {
+            conn = getConn();
+            stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+            // 设置游标拉取数量
+            stmt.setFetchSize(FETCH_SIZE_MAX);
+            stmt.setString(1, applicationName);
+            rs = stmt.executeQuery();
+
+            while (rs.next()) {
+                String elData = getStringFromResultSet(rs, elDataField);
+                String chainName = getStringFromResultSet(rs, chainNameField);
+
+                result.add(StrUtil.format(CHAIN_XML_PATTERN, XmlUtil.escape(chainName), elData));
+            }
+        } catch (Exception e) {
+            throw new ELSQLException(e.getMessage());
+        } finally {
+            // 关闭连接
+            close(conn, stmt, rs);
+        }
+
+        String chainsContent = CollUtil.join(result, StrUtil.EMPTY);
+
+        String nodesContent;
+        if (hasScriptData()) {
+            nodesContent = getScriptNodes();
+        } else {
+            nodesContent = StrUtil.EMPTY;
+        }
+
+        return StrUtil.format(XML_PATTERN, nodesContent, chainsContent);
+    }
+
+    public String getScriptNodes() {
+        List<String> result = new ArrayList<>();
+        Connection conn = null;
+        PreparedStatement stmt = null;
+        ResultSet rs = null;
+
+        String scriptTableName = sqlParserVO.getScriptTableName();
+        String scriptIdField = sqlParserVO.getScriptIdField();
+        String scriptDataField = sqlParserVO.getScriptDataField();
+        String scriptNameField = sqlParserVO.getScriptNameField();
+        String scriptTypeField = sqlParserVO.getScriptTypeField();
+        String scriptApplicationNameField = sqlParserVO.getScriptApplicationNameField();
+        String applicationName = sqlParserVO.getApplicationName();
+
+        if (StrUtil.isBlank(applicationName) || StrUtil.isBlank(scriptApplicationNameField)) {
+            throw new ELSQLException("You did not define the applicationName or scriptApplicationNameField property");
+        }
+
+        String sqlCmd = StrUtil.format(
+                SCRIPT_SQL_PATTERN,
+                scriptIdField,
+                scriptDataField,
+                scriptNameField,
+                scriptTypeField,
+                scriptTableName,
+                scriptApplicationNameField
+        );
+        try {
+            conn = getConn();
+            stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+            // 设置游标拉取数量
+            stmt.setFetchSize(FETCH_SIZE_MAX);
+            stmt.setString(1, applicationName);
+            rs = stmt.executeQuery();
+
+            while (rs.next()) {
+                String id = getStringFromResultSet(rs, scriptIdField);
+                String data = getStringFromResultSet(rs, scriptDataField);
+                String name = getStringFromResultSet(rs, scriptNameField);
+                String type = getStringFromResultSet(rs, scriptTypeField);
+
+                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));
+                }
+
+                result.add(StrUtil.format(NODE_ITEM_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, data));
+            }
+        } catch (Exception e) {
+            throw new ELSQLException(e.getMessage());
+        } finally {
+            // 关闭连接
+            close(conn, stmt, rs);
+        }
+        return StrUtil.format(NODE_XML_PATTERN, CollUtil.join(result, StrUtil.EMPTY));
+    }
+
+    /**
+     * 关闭连接
+     *
+     * @param conn conn
+     * @param stmt stmt
+     * @param rs   rs
+     */
+    private void close(Connection conn, PreparedStatement stmt, ResultSet rs) {
+        // 关闭连接
+        if (conn != null) {
+            try {
+                conn.close();
+            } catch (SQLException e) {
+                throw new ELSQLException(e.getMessage());
+            }
+        }
+        // 关闭 statement
+        if (stmt != null) {
+            try {
+                stmt.close();
+            } catch (SQLException e) {
+                throw new ELSQLException(e.getMessage());
+            }
+        }
+        //关闭结果集
+        if (rs != null) {
+            try {
+                rs.close();
+            } catch (SQLException e) {
+                throw new ELSQLException(e.getMessage());
+            }
+        }
+    }
+
+    private boolean hasScriptData() {
+        if (StrUtil.isBlank(sqlParserVO.getScriptTableName())) {
+            return false;
+        }
+
+        Connection conn = null;
+        PreparedStatement stmt = null;
+        ResultSet rs = null;
+        String sqlCmd = StrUtil.format(SCRIPT_SQL_CHECK_PATTERN,
+                sqlParserVO.getScriptTableName(),
+                sqlParserVO.getScriptApplicationNameField());
+        try {
+            conn = getConn();
+            stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+            stmt.setFetchSize(1);
+            stmt.setString(1, sqlParserVO.getApplicationName());
+            rs = stmt.executeQuery();
+            return rs.next();
+        } catch (Exception e) {
+            return false;
+        } finally {
+            // 关闭连接
+            close(conn, stmt, rs);
+        }
+    }
+
+
+    //#region get set method
+    private String getStringFromResultSet(ResultSet rs, String field) throws SQLException {
+        String data = rs.getString(field);
+        if (StrUtil.isBlank(data)) {
+            throw new ELSQLException(StrUtil.format("exist {} field value is empty", field));
+        }
+        return data;
+    }
+
+    private SQLParserVO getSqlParserVO() {
+        return sqlParserVO;
+    }
+
+    private void setSqlParserVO(SQLParserVO sqlParserVO) {
+        this.sqlParserVO = sqlParserVO;
+    }
 }
 }

+ 15 - 1
liteflow-script-plugin/liteflow-script-graaljs/src/main/java/com/yomahub/liteflow/script/graaljs/GraalJavaScriptExecutor.java

@@ -3,6 +3,9 @@ package com.yomahub.liteflow.script.graaljs;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.annotation.util.AnnoUtil;
+import com.yomahub.liteflow.context.ContextBean;
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
 import com.yomahub.liteflow.script.ScriptBeanManager;
 import com.yomahub.liteflow.script.ScriptBeanManager;
 import com.yomahub.liteflow.script.ScriptExecuteWrap;
 import com.yomahub.liteflow.script.ScriptExecuteWrap;
 import com.yomahub.liteflow.script.ScriptExecutor;
 import com.yomahub.liteflow.script.ScriptExecutor;
@@ -57,7 +60,13 @@ public class GraalJavaScriptExecutor implements ScriptExecutor {
             //比如你的自定义上下文为AbcContext,那么key就为:abcContext
             //比如你的自定义上下文为AbcContext,那么key就为:abcContext
             //这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
             //这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
             DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
             DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
-                String key = StrUtil.lowerFirst(o.getClass().getSimpleName());
+                ContextBean contextBean = AnnoUtil.getAnnotation(o.getClass(),ContextBean.class);
+                String key;
+                if(contextBean !=null && contextBean.value().trim().length()>0){
+                    key = contextBean.value();
+                }else{
+                    key = StrUtil.lowerFirst(o.getClass().getSimpleName());
+                }
                 bindings.putMember(key, o);
                 bindings.putMember(key, o);
             });
             });
 
 
@@ -103,4 +112,9 @@ public class GraalJavaScriptExecutor implements ScriptExecutor {
     public void cleanCache() {
     public void cleanCache() {
         scriptMap.clear();
         scriptMap.clear();
     }
     }
+
+    @Override
+    public ScriptTypeEnum scriptType() {
+        return ScriptTypeEnum.JS;
+    }
 }
 }

+ 3 - 2
liteflow-script-plugin/liteflow-script-groovy/src/main/java/com/yomahub/liteflow/script/groovy/GroovyScriptExecutor.java

@@ -1,5 +1,6 @@
 package com.yomahub.liteflow.script.groovy;
 package com.yomahub.liteflow.script.groovy;
 
 
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
 import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
 import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
 
 
 /**
 /**
@@ -10,7 +11,7 @@ import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
 public class GroovyScriptExecutor extends JSR223ScriptExecutor {
 public class GroovyScriptExecutor extends JSR223ScriptExecutor {
 
 
     @Override
     @Override
-    protected String scriptEngineName() {
-        return "groovy";
+    public ScriptTypeEnum scriptType() {
+        return ScriptTypeEnum.GROOVY;
     }
     }
 }
 }

+ 5 - 4
liteflow-script-plugin/liteflow-script-javascript/src/main/java/com/yomahub/liteflow/script/javascript/JavaScriptExecutor.java

@@ -1,6 +1,7 @@
 package com.yomahub.liteflow.script.javascript;
 package com.yomahub.liteflow.script.javascript;
 
 
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
 import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
 import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
 /**
 /**
  * JavaScript脚本语言的执行器实现
  * JavaScript脚本语言的执行器实现
@@ -10,12 +11,12 @@ import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
 public class JavaScriptExecutor extends JSR223ScriptExecutor {
 public class JavaScriptExecutor extends JSR223ScriptExecutor {
 
 
     @Override
     @Override
-    protected String scriptEngineName() {
-        return "javascript";
+    protected String convertScript(String script) {
+        return StrUtil.format("function process(){{}} process();",script);
     }
     }
 
 
     @Override
     @Override
-    protected String convertScript(String script) {
-        return StrUtil.format("function process(){{}} process();",script);
+    public ScriptTypeEnum scriptType() {
+        return ScriptTypeEnum.JS;
     }
     }
 }
 }

+ 3 - 2
liteflow-script-plugin/liteflow-script-lua/src/main/java/com/yomahub/liteflow/script/lua/LuaScriptExecutor.java

@@ -2,6 +2,7 @@ package com.yomahub.liteflow.script.lua;
 
 
 import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
 import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
 import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
 
 
 import java.util.Arrays;
 import java.util.Arrays;
@@ -15,8 +16,8 @@ import java.util.stream.Collectors;
  */
  */
 public class LuaScriptExecutor extends JSR223ScriptExecutor {
 public class LuaScriptExecutor extends JSR223ScriptExecutor {
     @Override
     @Override
-    protected String scriptEngineName() {
-        return "luaj";
+    public ScriptTypeEnum scriptType() {
+        return ScriptTypeEnum.LUA;
     }
     }
 
 
     @Override
     @Override

+ 3 - 2
liteflow-script-plugin/liteflow-script-python/src/main/java/com/yomahub/liteflow/script/python/PythonScriptExecutor.java

@@ -2,6 +2,7 @@ package com.yomahub.liteflow.script.python;
 
 
 import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
 import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
 import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
 import java.util.Arrays;
 import java.util.Arrays;
 import java.util.List;
 import java.util.List;
@@ -15,8 +16,8 @@ import java.util.stream.Collectors;
 public class PythonScriptExecutor extends JSR223ScriptExecutor {
 public class PythonScriptExecutor extends JSR223ScriptExecutor {
 
 
     @Override
     @Override
-    protected String scriptEngineName() {
-        return "python";
+    public ScriptTypeEnum scriptType() {
+        return ScriptTypeEnum.PYTHON;
     }
     }
 
 
     @Override
     @Override

+ 15 - 1
liteflow-script-plugin/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java

@@ -8,6 +8,9 @@ import com.ql.util.express.DefaultContext;
 import com.ql.util.express.ExpressLoader;
 import com.ql.util.express.ExpressLoader;
 import com.ql.util.express.ExpressRunner;
 import com.ql.util.express.ExpressRunner;
 import com.ql.util.express.InstructionSet;
 import com.ql.util.express.InstructionSet;
+import com.yomahub.liteflow.annotation.util.AnnoUtil;
+import com.yomahub.liteflow.context.ContextBean;
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
 import com.yomahub.liteflow.script.ScriptBeanManager;
 import com.yomahub.liteflow.script.ScriptBeanManager;
 import com.yomahub.liteflow.script.ScriptExecuteWrap;
 import com.yomahub.liteflow.script.ScriptExecuteWrap;
 import com.yomahub.liteflow.slot.DataBus;
 import com.yomahub.liteflow.slot.DataBus;
@@ -69,7 +72,13 @@ public class QLExpressScriptExecutor implements ScriptExecutor {
             //比如你的自定义上下文为AbcContext,那么key就为:abcContext
             //比如你的自定义上下文为AbcContext,那么key就为:abcContext
             //这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
             //这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
             DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
             DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
-                String key = StrUtil.lowerFirst(o.getClass().getSimpleName());
+                ContextBean contextBean = AnnoUtil.getAnnotation(o.getClass(),ContextBean.class);
+                String key;
+                if(contextBean !=null && contextBean.value().trim().length()>0){
+                    key = contextBean.value();
+                }else{
+                    key = StrUtil.lowerFirst(o.getClass().getSimpleName());
+                }
                 context.put(key, o);
                 context.put(key, o);
             });
             });
 
 
@@ -108,4 +117,9 @@ public class QLExpressScriptExecutor implements ScriptExecutor {
         expressRunner.clearExpressCache();
         expressRunner.clearExpressCache();
         ReflectUtil.setFieldValue(expressRunner,"loader",new ExpressLoader(expressRunner));
         ReflectUtil.setFieldValue(expressRunner,"loader",new ExpressLoader(expressRunner));
     }
     }
+
+    @Override
+    public ScriptTypeEnum scriptType() {
+        return ScriptTypeEnum.QLEXPRESS;
+    }
 }
 }

+ 33 - 15
liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonPathContentParser.java

@@ -3,6 +3,7 @@ package com.yomahub.liteflow.spi.solon;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.stream.StreamUtil;
 import cn.hutool.core.util.CharsetUtil;
 import cn.hutool.core.util.CharsetUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
 import com.yomahub.liteflow.exception.ConfigErrorException;
 import com.yomahub.liteflow.exception.ConfigErrorException;
@@ -10,17 +11,42 @@ import com.yomahub.liteflow.spi.PathContentParser;
 import org.noear.solon.Utils;
 import org.noear.solon.Utils;
 
 
 import java.io.File;
 import java.io.File;
-import java.net.URI;
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.HashSet;
 import java.util.List;
 import java.util.List;
 import java.util.Set;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 
 public class SolonPathContentParser implements PathContentParser {
 public class SolonPathContentParser implements PathContentParser {
     @Override
     @Override
     public List<String> parseContent(List<String> pathList) throws Exception {
     public List<String> parseContent(List<String> pathList) throws Exception {
-        if(CollectionUtil.isEmpty(pathList)){
+        List<URL> allResource = getUrls(pathList);
+
+        //转换成内容List
+        List<String> contentList = new ArrayList<>();
+        for (URL resource : allResource) {
+            String content = IoUtil.read(resource.openStream(), CharsetUtil.CHARSET_UTF_8);
+            if (StrUtil.isNotBlank(content)) {
+                contentList.add(content);
+            }
+        }
+
+        return contentList;
+    }
+
+    @Override
+    public List<String> getFileAbsolutePath(List<String> pathList) throws Exception {
+        List<URL> allResource = getUrls(pathList);
+        return StreamUtil.of(allResource)
+                .map(URL::getPath)
+                .filter(FileUtil::isFile)
+                .collect(Collectors.toList());
+    }
+
+    private static List<URL> getUrls(List<String> pathList) throws MalformedURLException {
+        if (CollectionUtil.isEmpty(pathList)) {
             throw new ConfigErrorException("rule source must not be null");
             throw new ConfigErrorException("rule source must not be null");
         }
         }
 
 
@@ -34,27 +60,19 @@ public class SolonPathContentParser implements PathContentParser {
                     path = path.substring(ResourceUtils.CLASSPATH_URL_PREFIX.length());
                     path = path.substring(ResourceUtils.CLASSPATH_URL_PREFIX.length());
                 }
                 }
 
 
-                allResource.add(Utils.getResource(path));
+                if (Utils.getResource(path) != null) {
+                    allResource.add(Utils.getResource(path));
+                }
             }
             }
         }
         }
 
 
         //如果有多个资源,检查资源都是同一个类型,如果出现不同类型的配置,则抛出错误提示
         //如果有多个资源,检查资源都是同一个类型,如果出现不同类型的配置,则抛出错误提示
         Set<String> fileTypeSet = new HashSet<>();
         Set<String> fileTypeSet = new HashSet<>();
         allResource.forEach(resource -> fileTypeSet.add(FileUtil.extName(resource.getPath())));
         allResource.forEach(resource -> fileTypeSet.add(FileUtil.extName(resource.getPath())));
-        if (fileTypeSet.size() != 1) {
+        if (fileTypeSet.size() > 1) {
             throw new ConfigErrorException("config error,please use the same type of configuration");
             throw new ConfigErrorException("config error,please use the same type of configuration");
         }
         }
-
-        //转换成内容List
-        List<String> contentList = new ArrayList<>();
-        for (URL resource : allResource) {
-            String content = IoUtil.read(resource.openStream(), CharsetUtil.CHARSET_UTF_8);
-            if (StrUtil.isNotBlank(content)){
-                contentList.add(content);
-            }
-        }
-
-        return contentList;
+        return allResource;
     }
     }
 
 
     @Override
     @Override

+ 11 - 0
liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java

@@ -70,6 +70,17 @@ public class LiteflowProperty {
     //替补组件的class路径
     //替补组件的class路径
     private String substituteCmpClass;
     private String substituteCmpClass;
 
 
+    // 规则文件/脚本文件变更监听
+    private Boolean enableMonitorFile;
+
+    public Boolean getEnableMonitorFile() {
+        return enableMonitorFile;
+    }
+
+    public void setEnableMonitorFile(Boolean enableMonitorFile) {
+        this.enableMonitorFile = enableMonitorFile;
+    }
+
     public boolean isEnable() {
     public boolean isEnable() {
         return enable;
         return enable;
     }
     }

+ 1 - 0
liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java

@@ -47,6 +47,7 @@ public class LiteflowPropertyAutoConfiguration {
         liteflowConfig.setMainExecutorClass(property.getMainExecutorClass());
         liteflowConfig.setMainExecutorClass(property.getMainExecutorClass());
         liteflowConfig.setPrintExecutionLog(property.isPrintExecutionLog());
         liteflowConfig.setPrintExecutionLog(property.isPrintExecutionLog());
         liteflowConfig.setSubstituteCmpClass(property.getSubstituteCmpClass());
         liteflowConfig.setSubstituteCmpClass(property.getSubstituteCmpClass());
+        liteflowConfig.setEnableMonitorFile(property.getEnableMonitorFile());
         return liteflowConfig;
         return liteflowConfig;
     }
     }
 }
 }

+ 7 - 0
liteflow-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json

@@ -158,6 +158,13 @@
       "description": "Set period time to print monitor log.",
       "description": "Set period time to print monitor log.",
       "sourceType": "com.yomahub.liteflow.springboot.LiteflowMonitorProperty",
       "sourceType": "com.yomahub.liteflow.springboot.LiteflowMonitorProperty",
       "defaultValue": 300000
       "defaultValue": 300000
+    },
+    {
+      "name": "liteflow.enable-monitor-file",
+      "type": "java.lang.Boolean",
+      "description": "Set file change monitoring.",
+      "sourceType": "com.yomahub.liteflow.springboot.LiteflowMonitorProperty",
+      "defaultValue": false
     }
     }
   ]
   ]
 }
 }

+ 1 - 0
liteflow-spring-boot-starter/src/main/resources/META-INF/liteflow-default.properties

@@ -18,3 +18,4 @@ liteflow.monitor.enable-log=false
 liteflow.monitor.queue-limit=200
 liteflow.monitor.queue-limit=200
 liteflow.monitor.delay=300000
 liteflow.monitor.delay=300000
 liteflow.monitor.period=300000
 liteflow.monitor.period=300000
+liteflow.enable-monitor-file=false

+ 2 - 0
liteflow-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -0,0 +1,2 @@
+com.yomahub.liteflow.springboot.config.LiteflowPropertyAutoConfiguration
+com.yomahub.liteflow.springboot.config.LiteflowMainAutoConfiguration

+ 40 - 14
liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringPathContentParser.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.stream.StreamUtil;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.CharsetUtil;
 import cn.hutool.core.util.CharsetUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
@@ -13,15 +14,49 @@ import org.springframework.core.io.Resource;
 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 import org.springframework.core.io.support.ResourcePatternResolver;
 import org.springframework.core.io.support.ResourcePatternResolver;
 import org.springframework.util.ResourceUtils;
 import org.springframework.util.ResourceUtils;
+
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.HashSet;
 import java.util.List;
 import java.util.List;
 import java.util.Set;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 
 public class SpringPathContentParser implements PathContentParser {
 public class SpringPathContentParser implements PathContentParser {
     @Override
     @Override
     public List<String> parseContent(List<String> pathList) throws Exception {
     public List<String> parseContent(List<String> pathList) throws Exception {
-        if(CollectionUtil.isEmpty(pathList)){
+        List<Resource> allResource = getResources(pathList);
+
+        //转换成内容List
+        List<String> contentList = new ArrayList<>();
+        for (Resource resource : allResource) {
+            String content = IoUtil.read(resource.getInputStream(), CharsetUtil.CHARSET_UTF_8);
+            if (StrUtil.isNotBlank(content)) {
+                contentList.add(content);
+            }
+        }
+
+        return contentList;
+    }
+
+    @Override
+    public List<String> getFileAbsolutePath(List<String> pathList) throws Exception {
+        List<Resource> allResource = getResources(pathList);
+
+        return StreamUtil.of(allResource)
+                // 过滤非 file 类型 Resource
+                .filter(Resource::isFile)
+                .map(r -> {
+                    try {
+                        return r.getFile().getAbsolutePath();
+                    } catch (IOException e) {
+                        throw new RuntimeException(e);
+                    }
+                }).collect(Collectors.toList());
+    }
+
+    private List<Resource> getResources(List<String> pathList) throws IOException {
+        if (CollectionUtil.isEmpty(pathList)) {
             throw new ConfigErrorException("rule source must not be null");
             throw new ConfigErrorException("rule source must not be null");
         }
         }
 
 
@@ -30,12 +65,12 @@ public class SpringPathContentParser implements PathContentParser {
             String locationPattern;
             String locationPattern;
 
 
             //如果path是绝对路径且这个文件存在时,我们认为这是一个本地文件路径,而并非classpath路径
             //如果path是绝对路径且这个文件存在时,我们认为这是一个本地文件路径,而并非classpath路径
-            if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)){
+            if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)) {
                 locationPattern = ResourceUtils.FILE_URL_PREFIX + path;
                 locationPattern = ResourceUtils.FILE_URL_PREFIX + path;
             } else {
             } else {
                 if (!path.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) && !path.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) {
                 if (!path.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) && !path.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) {
                     locationPattern = ResourceUtils.CLASSPATH_URL_PREFIX + path;
                     locationPattern = ResourceUtils.CLASSPATH_URL_PREFIX + path;
-                }else{
+                } else {
                     locationPattern = path;
                     locationPattern = path;
                 }
                 }
             }
             }
@@ -53,19 +88,10 @@ public class SpringPathContentParser implements PathContentParser {
         if (fileTypeSet.size() > 1) {
         if (fileTypeSet.size() > 1) {
             throw new ConfigErrorException("config error,please use the same type of configuration");
             throw new ConfigErrorException("config error,please use the same type of configuration");
         }
         }
-
-        //转换成内容List
-        List<String> contentList = new ArrayList<>();
-        for (Resource resource : allResource) {
-            String content = IoUtil.read(resource.getInputStream(), CharsetUtil.CHARSET_UTF_8);
-            if (StrUtil.isNotBlank(content)){
-                contentList.add(content);
-            }
-        }
-
-        return contentList;
+        return allResource;
     }
     }
 
 
+
     @Override
     @Override
     public int priority() {
     public int priority() {
         return 1;
         return 1;

+ 41 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELDeclMultiSpringbootTest.java

@@ -0,0 +1,41 @@
+package com.yomahub.liteflow.test.monitorFile;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ClassPathResource;
+import cn.hutool.core.util.CharsetUtil;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+import java.io.File;
+
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/monitorFile/application.properties")
+@SpringBootTest(classes = MonitorFileELDeclMultiSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.monitorFile.cmp"})
+public class MonitorFileELDeclMultiSpringbootTest extends BaseTest {
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testMonitor() throws Exception{
+        String absolutePath = new ClassPathResource("classpath:/monitorFile/flow.el.xml").getAbsolutePath();
+        String content = FileUtil.readUtf8String(absolutePath);
+        String newContent = content.replace("THEN(a, b, c);", "THEN(a, c, b);");
+        FileUtil.writeString(newContent,new File(absolutePath), CharsetUtil.CHARSET_UTF_8);
+        Thread.sleep(2500);
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+        Assert.assertEquals("a==>c==>b", response.getExecuteStepStr());
+
+    }
+}

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

@@ -0,0 +1,28 @@
+package com.yomahub.liteflow.test.monitorFile.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+import java.util.Random;
+
+@LiteflowComponent
+public class CmpConfig {
+
+    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
+    public void processA(NodeComponent bindCmp) {
+        System.out.println("ACmp executed!");
+    }
+
+    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
+    public void processB(NodeComponent bindCmp) {
+        System.out.println("BCmp executed!");
+    }
+    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
+    public void process(NodeComponent bindCmp) {
+        System.out.println("BCmp executed!");
+    }
+}
+
+

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

@@ -0,0 +1,2 @@
+liteflow.rule-source=monitorFile/flow.el.xml
+liteflow.enable-monitor-file=true

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

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

+ 40 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELDeclSpringbootTest.java

@@ -0,0 +1,40 @@
+package com.yomahub.liteflow.test.monitorFile;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ClassPathResource;
+import cn.hutool.core.util.CharsetUtil;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+import java.io.File;
+
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/monitorFile/application.properties")
+@SpringBootTest(classes = MonitorFileELDeclSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.monitorFile.cmp"})
+public class MonitorFileELDeclSpringbootTest extends BaseTest {
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testMonitor() throws Exception{
+        String absolutePath = new ClassPathResource("classpath:/monitorFile/flow.el.xml").getAbsolutePath();
+        String content = FileUtil.readUtf8String(absolutePath);
+        String newContent = content.replace("THEN(a, b, c);", "THEN(a, c, b);");
+        FileUtil.writeString(newContent,new File(absolutePath), CharsetUtil.CHARSET_UTF_8);
+        Thread.sleep(2500);
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+        Assert.assertEquals("a==>c==>b", response.getExecuteStepStr());
+    }
+}

+ 24 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.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.monitorFile.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+import java.util.Random;
+
+@Component("a")
+public class ACmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("ACmp executed!");
+	}
+}

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

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.monitorFile.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+import java.util.Random;
+
+@Component("b")
+public class BCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("BCmp executed!");
+	}
+
+}

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

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.monitorFile.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+import java.util.Random;
+
+@Component("c")
+public class CCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 1 - 1
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/refreshRule/RefreshRuleELDeclSpringbootTest.java

@@ -46,7 +46,7 @@ public class RefreshRuleELDeclSpringbootTest extends BaseTest {
     public void testRefresh2() throws Exception{
     public void testRefresh2() throws Exception{
         new Thread(() -> {
         new Thread(() -> {
             try {
             try {
-                Thread.sleep(3000L);
+                Thread.sleep(2000L);
                 String content = ResourceUtil.readUtf8Str("classpath: /refreshRule/flow_update.el.xml");
                 String content = ResourceUtil.readUtf8Str("classpath: /refreshRule/flow_update.el.xml");
                 FlowBus.refreshFlowMetaData(FlowParserTypeEnum.TYPE_EL_XML, content);
                 FlowBus.refreshFlowMetaData(FlowParserTypeEnum.TYPE_EL_XML, content);
             } catch (Exception e) {
             } catch (Exception e) {

+ 2 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/monitorFile/application.properties

@@ -0,0 +1,2 @@
+liteflow.rule-source=monitorFile/flow.el.xml
+liteflow.enable-monitor-file=true

+ 7 - 0
liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/monitorFile/flow.el.xml

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

+ 40 - 0
liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/LiteflowMonitorFileTest.java

@@ -0,0 +1,40 @@
+package com.yomahub.liteflow.test.monitorFile;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ClassPathResource;
+import cn.hutool.core.util.CharsetUtil;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.core.FlowExecutorHolder;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+
+public class LiteflowMonitorFileTest extends BaseTest {
+
+    private static FlowExecutor flowExecutor;
+
+    @BeforeClass
+    public static void init() {
+        LiteflowConfig config = new LiteflowConfig();
+        config.setRuleSource("monitorFile/flow.el.xml");
+        config.setEnableMonitorFile(true);
+        flowExecutor = FlowExecutorHolder.loadInstance(config);
+    }
+
+    @Test
+    public void testMonitor() throws InterruptedException {
+        String absolutePath = new ClassPathResource("classpath:/monitorFile/flow.el.xml").getAbsolutePath();
+        String content = FileUtil.readUtf8String(absolutePath);
+        String newContent = content.replace("THEN(a, b, c);", "THEN(a, c, b);");
+        FileUtil.writeString(newContent, new File(absolutePath), CharsetUtil.CHARSET_UTF_8);
+        Thread.sleep(2500);
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+        Assert.assertEquals("a==>c==>b", response.getExecuteStepStr());
+    }
+
+}

+ 18 - 0
liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java

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

+ 19 - 0
liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java

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

+ 19 - 0
liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java

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

+ 13 - 0
liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/monitorFile/flow.el.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<flow>
+    <nodes>
+        <node id="a" class="com.yomahub.liteflow.test.multipleType.cmp.ACmp"/>
+        <node id="b" class="com.yomahub.liteflow.test.multipleType.cmp.BCmp"/>
+        <node id="c" class="com.yomahub.liteflow.test.multipleType.cmp.CCmp"/>
+    </nodes>
+
+    <chain name="chain1">
+        THEN(a, b, c);
+    </chain>
+
+</flow>

+ 55 - 0
liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/java/com/yomahub/liteflow/test/script/graaljs/contextbean/LiteFlowScriptContextbeanGraaljsTest.java

@@ -0,0 +1,55 @@
+package com.yomahub.liteflow.test.script.graaljs.contextbean;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import com.yomahub.liteflow.test.script.graaljs.contextbean.bean.CheckContext;
+import com.yomahub.liteflow.test.script.graaljs.contextbean.bean.Order2Context;
+import com.yomahub.liteflow.test.script.graaljs.contextbean.bean.OrderContext;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/contextbean/application.properties")
+@SpringBootTest(classes = LiteFlowScriptContextbeanGraaljsTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.script.graaljs.contextbean.cmp","com.yomahub.liteflow.test.script.graaljs.contextbean.bean"})
+public class LiteFlowScriptContextbeanGraaljsTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testContextBean1() throws Exception{
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", OrderContext.class, CheckContext.class, Order2Context.class);
+        Assert.assertTrue(response.isSuccess());
+        OrderContext orderContext = response.getContextBean(OrderContext.class);
+        CheckContext checkContext = response.getContextBean(CheckContext.class);
+        Order2Context order2Context = response.getContextBean(Order2Context.class);
+        Assert.assertEquals("order1", orderContext.getOrderNo());
+        Assert.assertEquals("d", checkContext.getSign());
+        Assert.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);
+        Assert.assertTrue(response.isSuccess());
+
+    }
+
+}

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

@@ -0,0 +1,27 @@
+package com.yomahub.liteflow.test.script.graaljs.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;
+    }
+}

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

@@ -0,0 +1,36 @@
+package com.yomahub.liteflow.test.script.graaljs.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;
+    }
+}

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

@@ -0,0 +1,39 @@
+package com.yomahub.liteflow.test.script.graaljs.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;
+    }
+}

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

+ 1 - 0
liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/resources/contextbean/application.properties

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

+ 30 - 0
liteflow-testcase-el/liteflow-testcase-el-script-graaljs-springboot/src/test/resources/contextbean/flow.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<flow>
+
+    <nodes>
+        <node id="d" type="script" language="js">
+            <![CDATA[
+                order.setOrderNo("order1")
+                checkContext.setSign(_meta.get("nodeId"))
+                order2Context.setOrderNo("order2")
+            ]]>
+        </node>
+
+        <node id="e" type="script" language="js">
+            <![CDATA[
+                var orderNo = order.getOrderNo()
+                var sign = checkContext.getSign()
+                var orderNo2 = order2Context.getOrderNo()
+            ]]>
+        </node>
+    </nodes>
+
+    <chain name="chain1">
+        THEN(a,b,c,d);
+    </chain>
+
+    <chain name="chain2">
+        THEN(a,b,c,e);
+    </chain>
+
+</flow>

+ 55 - 0
liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/contextbean/LiteFlowScriptContextbeanGroovyELTest.java

@@ -0,0 +1,55 @@
+package com.yomahub.liteflow.test.script.groovy.contextbean;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import com.yomahub.liteflow.test.script.groovy.contextbean.bean.CheckContext;
+import com.yomahub.liteflow.test.script.groovy.contextbean.bean.Order2Context;
+import com.yomahub.liteflow.test.script.groovy.contextbean.bean.OrderContext;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/contextbean/application.properties")
+@SpringBootTest(classes = LiteFlowScriptContextbeanGroovyELTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.script.groovy.contextbean.cmp","com.yomahub.liteflow.test.script.groovy.contextbean.bean"})
+public class LiteFlowScriptContextbeanGroovyELTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testContextBean1() throws Exception{
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", OrderContext.class, CheckContext.class, Order2Context.class);
+        Assert.assertTrue(response.isSuccess());
+        OrderContext orderContext = response.getContextBean(OrderContext.class);
+        CheckContext checkContext = response.getContextBean(CheckContext.class);
+        Order2Context order2Context = response.getContextBean(Order2Context.class);
+        Assert.assertEquals("order1", orderContext.getOrderNo());
+        Assert.assertEquals("sign1", checkContext.getSign());
+        Assert.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);
+        Assert.assertTrue(response.isSuccess());
+
+    }
+
+}

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

@@ -0,0 +1,27 @@
+package com.yomahub.liteflow.test.script.groovy.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;
+    }
+}

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

@@ -0,0 +1,36 @@
+package com.yomahub.liteflow.test.script.groovy.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;
+    }
+}

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

@@ -0,0 +1,39 @@
+package com.yomahub.liteflow.test.script.groovy.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;
+    }
+}

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

+ 1 - 0
liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/contextbean/application.properties

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

+ 33 - 0
liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/contextbean/flow.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<flow>
+
+    <nodes>
+        <node id="d" type="script" language="groovy">
+            <![CDATA[
+                order.setOrderNo("order1")
+                checkContext.setSign("sign1")
+                order2Context.setOrderNo("order2")
+            ]]>
+        </node>
+
+        <node id="e" type="script" language="groovy">
+            <![CDATA[
+                def orderNo = order.getOrderNo()
+                println orderNo
+                def sign = checkContext.getSign()
+                println sign
+                def orderNo2 = order2Context.getOrderNo()
+                println orderNo2
+            ]]>
+        </node>
+    </nodes>
+
+    <chain name="chain1">
+        THEN(a,b,c,d);
+    </chain>
+
+    <chain name="chain2">
+        THEN(a,b,c,e);
+    </chain>
+
+</flow>

+ 55 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/contextbean/LiteFlowScriptContextbeanJavaScriptTest.java

@@ -0,0 +1,55 @@
+package com.yomahub.liteflow.test.script.javascript.contextbean;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import com.yomahub.liteflow.test.script.javascript.contextbean.bean.CheckContext;
+import com.yomahub.liteflow.test.script.javascript.contextbean.bean.Order2Context;
+import com.yomahub.liteflow.test.script.javascript.contextbean.bean.OrderContext;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/contextbean/application.properties")
+@SpringBootTest(classes = LiteFlowScriptContextbeanJavaScriptTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.script.javascript.contextbean.cmp","com.yomahub.liteflow.test.script.javascript.contextbean.bean"})
+public class LiteFlowScriptContextbeanJavaScriptTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testContextBean1() throws Exception{
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", OrderContext.class, CheckContext.class, Order2Context.class);
+        Assert.assertTrue(response.isSuccess());
+        OrderContext orderContext = response.getContextBean(OrderContext.class);
+        CheckContext checkContext = response.getContextBean(CheckContext.class);
+        Order2Context order2Context = response.getContextBean(Order2Context.class);
+        Assert.assertEquals("order1", orderContext.getOrderNo());
+        Assert.assertEquals("sign1", checkContext.getSign());
+        Assert.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);
+        Assert.assertTrue(response.isSuccess());
+
+    }
+
+}

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff