Browse Source

feature #IASS9Z 新的java脚本插件,支持java8~java17的所有语法特性

everywhere.z 8 months ago
parent
commit
342f6329bf
26 changed files with 726 additions and 1 deletions
  1. 1 1
      liteflow-script-plugin/liteflow-script-java/src/main/java/com/yomahub/liteflow/script/java/JavaExecutor.java
  2. 28 0
      liteflow-script-plugin/liteflow-script-javax/pom.xml
  3. 6 0
      liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/body/BooleanScriptBody.java
  4. 5 0
      liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/body/CommonScriptBody.java
  5. 6 0
      liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/body/ForScriptBody.java
  6. 7 0
      liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/body/ScriptBody.java
  7. 6 0
      liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/body/SwitchScriptBody.java
  8. 97 0
      liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/javax/JavaxExecutor.java
  9. 2 0
      liteflow-script-plugin/liteflow-script-javax/src/main/resources/META-INF/services/com.yomahub.liteflow.script.ScriptExecutor
  10. 38 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/pom.xml
  11. 24 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/BaseTest.java
  12. 38 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/ScriptJavaxCommonELTest.java
  13. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/cmp/ACmp.java
  14. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/cmp/BCmp.java
  15. 21 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/cmp/CCmp.java
  16. 24 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/cmp/DCmp.java
  17. 28 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/cmp/Person.java
  18. 26 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/cmp/TestDomain.java
  19. 124 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/remove/LiteFlowJavaxScriptRemoveELTest.java
  20. 66 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/validate/ValidateJavaxScriptComponentTest.java
  21. 1 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/resources/common/application.properties
  22. 77 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/resources/common/flow.xml
  23. 1 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/resources/remove/application.properties
  24. 50 0
      liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/resources/remove/flow.xml
  25. 1 0
      liteflow-testcase-el/pom.xml
  26. 7 0
      pom.xml

+ 1 - 1
liteflow-script-plugin/liteflow-script-java/src/main/java/com/yomahub/liteflow/script/java/JavaExecutor.java

@@ -85,6 +85,6 @@ public class JavaExecutor extends ScriptExecutor {
         return "import com.yomahub.liteflow.script.body.JaninoCommonScriptBody;\n" +
                 script1 + "\n" +
                 StrUtil.format("{} item = new {}();\n", className, className) +
-                "if (item instanceof JaninoCommonScriptBody){item.body(_meta);return null;}else{return item.body(_meta);}";
+                "if (JaninoCommonScriptBody.class.isInstance(item)){item.body(_meta);return null;}else{return item.body(_meta);}";
     }
 }

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

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

+ 6 - 0
liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/body/BooleanScriptBody.java

@@ -0,0 +1,6 @@
+package com.yomahub.liteflow.script.body;
+
+
+public interface BooleanScriptBody extends ScriptBody<Boolean> {
+
+}

+ 5 - 0
liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/body/CommonScriptBody.java

@@ -0,0 +1,5 @@
+package com.yomahub.liteflow.script.body;
+
+public interface CommonScriptBody extends ScriptBody<Void> {
+
+}

+ 6 - 0
liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/body/ForScriptBody.java

@@ -0,0 +1,6 @@
+package com.yomahub.liteflow.script.body;
+
+
+public interface ForScriptBody extends ScriptBody<Integer> {
+
+}

+ 7 - 0
liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/body/ScriptBody.java

@@ -0,0 +1,7 @@
+package com.yomahub.liteflow.script.body;
+
+import com.yomahub.liteflow.script.ScriptExecuteWrap;
+
+public interface ScriptBody<T> {
+    T body(ScriptExecuteWrap wrap);
+}

+ 6 - 0
liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/body/SwitchScriptBody.java

@@ -0,0 +1,6 @@
+package com.yomahub.liteflow.script.body;
+
+
+public interface SwitchScriptBody extends ScriptBody<String> {
+
+}

+ 97 - 0
liteflow-script-plugin/liteflow-script-javax/src/main/java/com/yomahub/liteflow/script/javax/JavaxExecutor.java

@@ -0,0 +1,97 @@
+package com.yomahub.liteflow.script.javax;
+
+import cn.hutool.core.util.ReUtil;
+import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
+import com.yomahub.liteflow.script.ScriptExecuteWrap;
+import com.yomahub.liteflow.script.ScriptExecutor;
+import com.yomahub.liteflow.script.exception.ScriptLoadException;
+import com.yomahub.liteflow.util.CopyOnWriteHashMap;
+import org.noear.liquor.eval.CodeSpec;
+import org.noear.liquor.eval.ScriptEvaluator;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class JavaxExecutor extends ScriptExecutor {
+    private final Map<String, CodeSpec> compiledScriptMap = new CopyOnWriteHashMap<>();
+
+    private ScriptEvaluator scriptEvaluator;
+
+    @Override
+    public ScriptExecutor init() {
+        scriptEvaluator = new ScriptEvaluator();
+        scriptEvaluator.setPrintable(true);
+        return this;
+    }
+
+    @Override
+    public void load(String nodeId, String script) {
+        try{
+            compiledScriptMap.put(nodeId, (CodeSpec) compile(script));
+        }catch (Exception e){
+            String errorMsg = StrUtil.format("script loading error for node[{}],error msg:{}", nodeId, e.getMessage());
+            throw new ScriptLoadException(errorMsg);
+        }
+
+    }
+
+    @Override
+    public void unLoad(String nodeId) {
+        compiledScriptMap.remove(nodeId);
+    }
+
+    @Override
+    public List<String> getNodeIds() {
+        return new ArrayList<>(compiledScriptMap.keySet());
+    }
+
+    @Override
+    public Object executeScript(ScriptExecuteWrap wrap) throws Exception {
+        if (!compiledScriptMap.containsKey(wrap.getNodeId())) {
+            String errorMsg = StrUtil.format("script for node[{}] is not loaded", wrap.getNodeId());
+            throw new ScriptLoadException(errorMsg);
+        }
+        CodeSpec codeSpec = compiledScriptMap.get(wrap.getNodeId());
+        return scriptEvaluator.eval(codeSpec, wrap);
+    }
+
+    @Override
+    public void cleanCache() {
+        compiledScriptMap.clear();
+    }
+
+    @Override
+    public ScriptTypeEnum scriptType() {
+        return ScriptTypeEnum.JAVA;
+    }
+
+    @Override
+    public Object compile(String script) throws Exception {
+        CodeSpec codeSpec = new CodeSpec(convertScript(script))
+                .returnType(Object.class)
+                .parameters(new String[] {"_meta"}, new Class[] {ScriptExecuteWrap.class});
+        scriptEvaluator.getClazz(codeSpec);
+        return codeSpec;
+    }
+
+    private String convertScript(String script){
+        //替换掉public,private,protected等修饰词
+        String script1 = script.replaceAll("public class", "class")
+                .replaceAll("private class", "class")
+                .replaceAll("protected class", "class");
+
+        //分析出class的具体名称
+        String className = ReUtil.getGroup1("class\\s+(\\w+)\\s+implements", script1);
+
+        if (StrUtil.isBlank(className)){
+            throw new RuntimeException("cannot find class defined");
+        }
+
+        return "import com.yomahub.liteflow.script.body.CommonScriptBody;\n" +
+                script1 + "\n" +
+                StrUtil.format("{} item = new {}();\n", className, className) +
+                "if (CommonScriptBody.class.isInstance(item)){item.body(_meta);return null;}else{return item.body(_meta);}";
+    }
+}

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

@@ -0,0 +1,2 @@
+# Java的实现
+com.yomahub.liteflow.script.javax.JavaxExecutor

+ 38 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/pom.xml

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

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

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

+ 38 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/ScriptJavaxCommonELTest.java

@@ -0,0 +1,38 @@
+package com.yomahub.liteflow.test.script.javax.common;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.slot.DefaultContext;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import javax.annotation.Resource;
+
+@ExtendWith(SpringExtension.class)
+@TestPropertySource(value = "classpath:/common/application.properties")
+@SpringBootTest(classes = ScriptJavaxCommonELTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.script.javax.common.cmp" })
+public class ScriptJavaxCommonELTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    // 测试普通脚本节点
+    @Test
+    public void testCommon1() {
+        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+        DefaultContext context = response.getFirstContextBean();
+        Assertions.assertTrue(response.isSuccess());
+        Assertions.assertEquals(6, (int)context.getData("s1"));
+        Assertions.assertEquals("hello,jack", context.getData("hi"));
+        Assertions.assertEquals(47100, (Integer) context.getData("salary"));
+    }
+}

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

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

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

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

+ 21 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/cmp/CCmp.java

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

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

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

+ 28 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/cmp/Person.java

@@ -0,0 +1,28 @@
+package com.yomahub.liteflow.test.script.javax.common.cmp;
+
+public class Person {
+    private String name;
+
+    private Integer salary;
+
+    public Person(String name, Integer salary) {
+        this.name = name;
+        this.salary = salary;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Integer getSalary() {
+        return salary;
+    }
+
+    public void setSalary(Integer salary) {
+        this.salary = salary;
+    }
+}

+ 26 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/common/cmp/TestDomain.java

@@ -0,0 +1,26 @@
+package com.yomahub.liteflow.test.script.javax.common.cmp;
+
+import cn.hutool.core.collection.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.function.ToIntFunction;
+
+@Component
+public class TestDomain {
+
+    public String sayHello(String name){
+        return "hello," + name;
+    }
+
+    public static void main(String[] args) {
+        List<Person> personList = ListUtil.toList(
+                new Person("jack", 15000),
+                new Person("tom", 13500),
+                new Person("peter", 18600)
+                );
+
+        int totalSalary = personList.stream().mapToInt(Person::getSalary).sum();
+        System.out.println(totalSalary);
+    }
+}

+ 124 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/remove/LiteFlowJavaxScriptRemoveELTest.java

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

+ 66 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/java/com/yomahub/liteflow/test/script/javax/validate/ValidateJavaxScriptComponentTest.java

@@ -0,0 +1,66 @@
+package com.yomahub.liteflow.test.script.javax.validate;
+
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
+import com.yomahub.liteflow.script.validator.ScriptValidator;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest(classes = ValidateJavaxScriptComponentTest.class)
+@EnableAutoConfiguration
+public class ValidateJavaxScriptComponentTest {
+    @Test
+    public void testJavaScriptComponentValidateFunction(){
+        String correctScript = "import com.alibaba.fastjson2.JSON;\n" +
+                "            import com.yomahub.liteflow.slot.DefaultContext;\n" +
+                "            import com.yomahub.liteflow.spi.holder.ContextAwareHolder;\n" +
+                "            import com.yomahub.liteflow.test.script.java.common.cmp.TestDomain;\n" +
+                "            import com.yomahub.liteflow.script.body.CommonScriptBody;\n" +
+                "            import com.yomahub.liteflow.script.ScriptExecuteWrap;\n" +
+                "\n" +
+                "            public class Demo implements CommonScriptBody {\n" +
+                "                public Void body(ScriptExecuteWrap wrap) {\n" +
+                "                    int v1 = 2;\n" +
+                "                    int v2 = 3;\n" +
+                "                    DefaultContext ctx = wrap.getCmp().getFirstContextBean();\n" +
+                "                    ctx.setData(\"s1\", v1 * v2);\n" +
+                "\n" +
+                "                    TestDomain domain = ContextAwareHolder.loadContextAware().getBean(TestDomain.class);\n" +
+                "                    System.out.println(JSON.toJSONString(domain));\n" +
+                "                    String str = domain.sayHello(\"jack\");\n" +
+                "                    ctx.setData(\"hi\", str);\n" +
+                "\n" +
+                "                    return null;\n" +
+                "                }\n" +
+                "            }";
+        // 未指定类型名错误
+        String wrongScript = "import com.alibaba.fastjson2.JSON;\n" +
+                "            import com.yomahub.liteflow.slot.DefaultContext;\n" +
+                "            import com.yomahub.liteflow.spi.holder.ContextAwareHolder;\n" +
+                "            import com.yomahub.liteflow.test.script.java.common.cmp.TestDomain;\n" +
+                "            import com.yomahub.liteflow.script.body.CommonScriptBody;\n" +
+                "            import com.yomahub.liteflow.script.ScriptExecuteWrap;\n" +
+                "\n" +
+                "            public class Demo implements CommonScriptBody {\n" +
+                "                public Void body(ScriptExecuteWrap wrap) {\n" +
+                "                    v1 = 2;\n" +
+                "                    int v2 = 3;\n" +
+                "                    DefaultContext ctx = wrap.getCmp().getFirstContextBean();\n" +
+                "                    ctx.setData(\"s1\", v1 * v2);\n" +
+                "\n" +
+                "                    TestDomain domain = ContextAwareHolder.loadContextAware().getBean(TestDomain.class);\n" +
+                "                    System.out.println(JSON.toJSONString(domain));\n" +
+                "                    String str = domain.sayHello(\"jack\");\n" +
+                "                    ctx.setData(\"hi\", str);\n" +
+                "\n" +
+                "                    return null;\n" +
+                "                }\n" +
+                "            }";
+        Assertions.assertTrue(ScriptValidator.validate(correctScript));
+        Assertions.assertFalse(ScriptValidator.validate(wrongScript));
+
+        Assertions.assertTrue(ScriptValidator.validate(correctScript, ScriptTypeEnum.JAVA));
+        Assertions.assertFalse(ScriptValidator.validate(correctScript, ScriptTypeEnum.GROOVY));
+    }
+}

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

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

+ 77 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/resources/common/flow.xml

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE flow PUBLIC  "liteflow" "liteflow.dtd">
+<flow>
+    <nodes>
+        <node id="s1" name="普通脚本1" type="script" language="java">
+            <![CDATA[
+            import cn.hutool.core.collection.ListUtil;
+            import com.alibaba.fastjson2.JSON;
+            import com.yomahub.liteflow.script.body.CommonScriptBody;
+            import com.yomahub.liteflow.slot.DefaultContext;
+            import com.yomahub.liteflow.spi.holder.ContextAwareHolder;
+            import com.yomahub.liteflow.test.script.javax.common.cmp.Person;
+            import com.yomahub.liteflow.test.script.javax.common.cmp.TestDomain;
+            import com.yomahub.liteflow.script.ScriptExecuteWrap;
+            import java.util.List;
+            import java.util.function.ToIntFunction;
+
+            public class Demo implements CommonScriptBody {
+                public Void body(ScriptExecuteWrap wrap) {
+                    int v1 = 2;
+                    int v2 = 3;
+                    DefaultContext ctx = wrap.getCmp().getFirstContextBean();
+                    ctx.setData("s1", v1 * v2);
+
+                    TestDomain domain = ContextAwareHolder.loadContextAware().getBean(TestDomain.class);
+                    System.out.println(JSON.toJSONString(domain));
+                    String str = domain.sayHello("jack");
+                    ctx.setData("hi", str);
+
+                    List<Person> personList = ListUtil.toList(
+                            new Person("jack", 15000),
+                            new Person("tom", 13500),
+                            new Person("peter", 18600)
+                    );
+
+                    int totalSalary = personList.stream().mapToInt(Person::getSalary).sum();
+
+                    System.out.println(totalSalary);
+                    ctx.setData("salary", 47100);
+
+                    return null;
+                }
+            }
+            ]]>
+        </node>
+
+        <node id="s2" name="循环脚本1" type="for_script" language="java">
+            <![CDATA[
+            import com.yomahub.liteflow.script.body.ForScriptBody;
+            import com.yomahub.liteflow.script.ScriptExecuteWrap;
+
+            public class Demo implements ForScriptBody {
+                public Integer body(ScriptExecuteWrap wrap) {
+                    return 2;
+                }
+            }
+            ]]>
+        </node>
+
+        <node id="s3" name="选择脚本" type="switch_script" language="java">
+            <![CDATA[
+            import com.yomahub.liteflow.script.ScriptExecuteWrap;
+            import com.yomahub.liteflow.script.body.SwitchScriptBody;
+
+            public class Demo implements SwitchScriptBody {
+                public String body(ScriptExecuteWrap wrap) {
+                    return "b";
+                }
+            }
+            ]]>
+        </node>
+    </nodes>
+
+    <chain name="chain1">
+        THEN(FOR(s2).DO(THEN(a, b, c, s1)), SWITCH(s3).TO(a,b));
+    </chain>
+</flow>

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

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

+ 50 - 0
liteflow-testcase-el/liteflow-testcase-el-script-javax-springboot/src/test/resources/remove/flow.xml

@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<flow>
+    <nodes>
+        <node id="s1" name="普通脚本1" type="script" language="java">
+            <![CDATA[
+            import com.yomahub.liteflow.slot.DefaultContext;
+            import com.yomahub.liteflow.script.body.CommonScriptBody;
+            import com.yomahub.liteflow.script.ScriptExecuteWrap;
+
+            public class Demo implements CommonScriptBody {
+                public Void body(ScriptExecuteWrap wrap) {
+                    int a = 1;
+                    int b = 2;
+                    int c = 3;
+                    DefaultContext ctx = wrap.getCmp().getFirstContextBean();
+                    ctx.setData("s1", a + b + c);
+                    return null;
+                }
+            }
+            ]]>
+        </node>
+
+        <node id="s2" name="普通脚本2" type="script" language="java">
+            <![CDATA[
+            import com.yomahub.liteflow.slot.DefaultContext;
+            import com.yomahub.liteflow.script.body.CommonScriptBody;
+            import com.yomahub.liteflow.script.ScriptExecuteWrap;
+
+            public class Demo implements CommonScriptBody {
+                public Void body(ScriptExecuteWrap wrap) {
+                    int a = 1;
+                    int b = 2;
+                    int c = 3;
+                    DefaultContext ctx = wrap.getCmp().getFirstContextBean();
+                    ctx.setData("s2", a * b + c);
+                    return null;
+                }
+            }
+            ]]>
+        </node>
+    </nodes>
+
+    <chain name="chain1">
+        THEN(s1);
+    </chain>
+
+    <chain name="chain2">
+        THEN(s2);
+    </chain>
+</flow>

+ 1 - 0
liteflow-testcase-el/pom.xml

@@ -42,6 +42,7 @@
         <module>liteflow-testcase-el-routechain</module>
         <module>liteflow-testcase-el-script-kotlin-springboot</module>
         <module>liteflow-testcase-el-sql-solon</module>
+        <module>liteflow-testcase-el-script-javax-springboot</module>
     </modules>
 
     <build>

+ 7 - 0
pom.xml

@@ -77,6 +77,7 @@
 		<redisson.version>3.21.0</redisson.version>
 		<janino.version>3.1.12</janino.version>
 		<kotlin.version>1.9.23</kotlin.version>
+		<liquor.version>1.2.7-SNAPSHOT</liquor.version>
 	</properties>
 
 	<dependencyManagement>
@@ -320,6 +321,11 @@
 				<artifactId>kotlin-scripting-jsr223</artifactId>
 				<version>${kotlin.version}</version>
 			</dependency>
+			<dependency>
+				<groupId>org.noear</groupId>
+				<artifactId>liquor-eval</artifactId>
+				<version>${liquor.version}</version>
+			</dependency>
 		</dependencies>
 	</dependencyManagement>
 
@@ -442,6 +448,7 @@
 		<module>liteflow-solon-plugin</module>
 		<module>liteflow-testcase-el</module>
         <module>liteflow-el-builder</module>
+		<module>liteflow-script-plugin/liteflow-script-javax</module>
 	</modules>
 
 	<distributionManagement>