diff --git a/liteflow-core/pom.xml b/liteflow-core/pom.xml
index d4f317d96..2b907e482 100644
--- a/liteflow-core/pom.xml
+++ b/liteflow-core/pom.xml
@@ -13,6 +13,12 @@
+
+ com.yomahub
+ liteflow-script-common
+ ${project.version}
+
+
cn.hutool
hutool-core
diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptNodeComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptNodeComponent.java
new file mode 100644
index 000000000..7d7c322af
--- /dev/null
+++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptNodeComponent.java
@@ -0,0 +1,20 @@
+package com.yomahub.liteflow.core;
+
+import com.yomahub.liteflow.script.ScriptFactory;
+
+/**
+ * 脚本组件类
+ * @author Bryan.Zhang
+ * @since 2.5.11
+ */
+public class ScriptNodeComponent extends NodeComponent{
+
+ @Override
+ public void process() throws Exception {
+ ScriptFactory.loadInstance().getScriptExecutor().execute(getNodeId(), getSlotIndex());
+ }
+
+ public void loadScript(String script) {
+ ScriptFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
+ }
+}
diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java
index 5d284cb0b..285b98c39 100644
--- a/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java
+++ b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java
@@ -14,6 +14,7 @@ import java.util.Map;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.core.ScriptNodeComponent;
import com.yomahub.liteflow.entity.data.DataBus;
import com.yomahub.liteflow.entity.data.Slot;
import com.yomahub.liteflow.enums.ExecuteTypeEnum;
diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java
index c84b41b71..7b2e4d558 100644
--- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java
+++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java
@@ -12,6 +12,7 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.core.ScriptNodeComponent;
import com.yomahub.liteflow.entity.flow.Chain;
import com.yomahub.liteflow.entity.flow.Node;
import com.yomahub.liteflow.enums.FlowParserTypeEnum;
@@ -23,6 +24,7 @@ import com.yomahub.liteflow.util.SpringAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
@@ -72,14 +74,19 @@ public class FlowBus {
public static void addNode(String nodeId, String name, String cmpClazzStr) throws Exception {
if (containNode(nodeId)) return;
Class cmpClazz = (Class) Class.forName(cmpClazzStr);
- addNode(nodeId, name ,cmpClazz);
+ addNode(nodeId, name ,cmpClazz, null);
+ }
+
+ public static void addScriptNode(String nodeId, String name, String script){
+ if (containNode(nodeId)) return;
+ addNode(nodeId, name , ScriptNodeComponent.class, script);
}
public static void addNode(String nodeId, Class extends NodeComponent> cmpClazz){
- addNode(nodeId, null, cmpClazz);
+ addNode(nodeId, null, cmpClazz, null);
}
- public static void addNode(String nodeId, String name, Class extends NodeComponent> cmpClazz) {
+ public static void addNode(String nodeId, String name, Class extends NodeComponent> cmpClazz, String script) {
if (containNode(nodeId)) return;
try {
//以node方式配置,本质上是为了适配无spring的环境,如果有spring环境,其实不用这么配置
@@ -92,6 +99,11 @@ public class FlowBus {
cmpInstance.setNodeId(nodeId);
cmpInstance.setName(name);
cmpInstance.setSelf(cmpInstance);
+
+ //如果是脚本节点,则还要加载script脚本
+ if (cmpClazz.equals(ScriptNodeComponent.class) && StrUtil.isNotBlank(script)){
+ ((ScriptNodeComponent)cmpInstance).loadScript(script);
+ }
nodeMap.put(nodeId, new Node(cmpInstance));
} catch (Exception e) {
String error = StrUtil.format("component[{}] register error", cmpClazz.getName());
diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java
index aca934c10..a9ad0bcb9 100644
--- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java
+++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java
@@ -2,6 +2,7 @@ package com.yomahub.liteflow.parser;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.common.LocalDefaultFlowConstant;
import com.yomahub.liteflow.core.NodeComponent;
@@ -52,23 +53,34 @@ public abstract class XmlFlowParser extends FlowParser {
//xml形式的主要解析过程
public void parseDocument(List documentList) throws Exception {
try {
+ //先进行Spring上下文中的节点的判断
+ for (Entry componentEntry : ComponentScanner.nodeComponentMap.entrySet()) {
+ if (!FlowBus.containNode(componentEntry.getKey())) {
+ FlowBus.addNode(componentEntry.getKey(), new Node(componentEntry.getValue()));
+ }
+ }
+
for (Document document : documentList) {
Element rootElement = document.getRootElement();
- //判断是以spring方式注册节点,还是以xml方式注册
- if (ComponentScanner.nodeComponentMap.isEmpty()) {
- // 解析node节点
- List nodeList = rootElement.element("nodes").elements("node");
- String id, name, clazz;
+ Element nodesElement = rootElement.element("nodes");
+ // 当存在节点定义时,解析node节点
+ if (ObjectUtil.isNotNull(nodesElement)){
+ List nodeList = nodesElement.elements("node");
+ String id, name, clazz, script;
for (Element e : nodeList) {
id = e.attributeValue("id");
name = e.attributeValue("name");
clazz = e.attributeValue("class");
- FlowBus.addNode(id, name, clazz);
- }
- } else {
- for (Entry componentEntry : ComponentScanner.nodeComponentMap.entrySet()) {
- if (!FlowBus.containNode(componentEntry.getKey())) {
- FlowBus.addNode(componentEntry.getKey(), new Node(componentEntry.getValue()));
+
+ if (StrUtil.isNotBlank(clazz)){
+ if (!FlowBus.containNode(id)){
+ FlowBus.addNode(id, name, clazz);
+ }
+ }else{
+ if (!FlowBus.containNode(id)){
+ script = e.getTextTrim();
+ FlowBus.addScriptNode(id, name, script);
+ }
}
}
}
diff --git a/liteflow-script-common/pom.xml b/liteflow-script-common/pom.xml
new file mode 100644
index 000000000..d45d0dc0b
--- /dev/null
+++ b/liteflow-script-common/pom.xml
@@ -0,0 +1,26 @@
+
+
+
+ liteflow
+ com.yomahub
+ 2.5.11
+
+ 4.0.0
+
+ liteflow-script-common
+
+
+
+ org.springframework
+ spring-beans
+ true
+
+
+ cn.hutool
+ hutool-core
+ true
+
+
+
\ No newline at end of file
diff --git a/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/ScriptExecutor.java b/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/ScriptExecutor.java
new file mode 100644
index 000000000..a38a2de26
--- /dev/null
+++ b/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/ScriptExecutor.java
@@ -0,0 +1,15 @@
+package com.yomahub.liteflow.script;
+
+/**
+ * 脚本执行器
+ * @author Bryan.Zhang
+ * @since 2.5.11
+ */
+public interface ScriptExecutor {
+
+ ScriptExecutor init();
+
+ void load(String nodeId, String script);
+
+ void execute(String nodeId, int slotIndex);
+}
diff --git a/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/ScriptFactory.java b/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/ScriptFactory.java
new file mode 100644
index 000000000..38e398b79
--- /dev/null
+++ b/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/ScriptFactory.java
@@ -0,0 +1,30 @@
+package com.yomahub.liteflow.script;
+
+import cn.hutool.core.util.ObjectUtil;
+
+import java.util.ServiceLoader;
+
+public class ScriptFactory {
+
+ private static ScriptFactory scriptFactory;
+
+ private static ScriptExecutor scriptExecutor;
+
+ public static ScriptFactory loadInstance(){
+ if (ObjectUtil.isNull(scriptFactory)){
+ scriptFactory = new ScriptFactory();
+ }
+ return scriptFactory;
+ }
+
+ public ScriptExecutor getScriptExecutor(){
+ if (ObjectUtil.isNull(scriptExecutor)){
+ ServiceLoader loader = ServiceLoader.load(ScriptExecutor.class);
+ if (loader.iterator().hasNext()){
+ scriptExecutor = loader.iterator().next().init();
+ return scriptExecutor;
+ }
+ }
+ return scriptExecutor;
+ }
+}
diff --git a/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/exception/ScriptExecuteException.java b/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/exception/ScriptExecuteException.java
new file mode 100644
index 000000000..d8b1d4d92
--- /dev/null
+++ b/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/exception/ScriptExecuteException.java
@@ -0,0 +1,27 @@
+
+package com.yomahub.liteflow.script.exception;
+
+/**
+ * 脚本运行异常
+ * @author Bryan.Zhang
+ * @since 2.5.11
+ */
+public class ScriptExecuteException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ /** 异常信息 */
+ private String message;
+
+ public ScriptExecuteException(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/exception/ScriptLoadException.java b/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/exception/ScriptLoadException.java
new file mode 100644
index 000000000..8fcf609f0
--- /dev/null
+++ b/liteflow-script-common/src/main/java/com/yomahub/liteflow/script/exception/ScriptLoadException.java
@@ -0,0 +1,27 @@
+
+package com.yomahub.liteflow.script.exception;
+
+/**
+ * 脚本加载异常
+ * @author Bryan.Zhang
+ * @since 2.5.11
+ */
+public class ScriptLoadException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ /** 异常信息 */
+ private String message;
+
+ public ScriptLoadException(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/liteflow-script-qlexpress/pom.xml b/liteflow-script-qlexpress/pom.xml
new file mode 100644
index 000000000..78bc08320
--- /dev/null
+++ b/liteflow-script-qlexpress/pom.xml
@@ -0,0 +1,31 @@
+
+
+
+ liteflow
+ com.yomahub
+ 2.5.11
+
+ 4.0.0
+
+ liteflow-script-qlexpress
+
+
+
+ com.yomahub
+ liteflow-script-common
+ ${project.version}
+
+
+ com.yomahub
+ liteflow-core
+ ${project.version}
+ true
+
+
+ com.alibaba
+ QLExpress
+
+
+
\ No newline at end of file
diff --git a/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java b/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java
new file mode 100644
index 000000000..29b11a33f
--- /dev/null
+++ b/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java
@@ -0,0 +1,55 @@
+package com.yomahub.liteflow.script.qlexpress;
+
+import cn.hutool.core.util.StrUtil;
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.yomahub.liteflow.entity.data.DataBus;
+import com.yomahub.liteflow.entity.data.Slot;
+import com.yomahub.liteflow.script.ScriptExecutor;
+import com.yomahub.liteflow.script.exception.ScriptExecuteException;
+import com.yomahub.liteflow.script.exception.ScriptLoadException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class QLExpressScriptExecutor implements ScriptExecutor {
+
+ private final Logger log = LoggerFactory.getLogger(this.getClass());
+
+ private ExpressRunner expressRunner;
+
+ @Override
+ public ScriptExecutor init() {
+ expressRunner = new ExpressRunner();
+ return this;
+ }
+
+ @Override
+ public void load(String nodeId, String script) {
+ try{
+ expressRunner.loadMutilExpress(nodeId, script);
+ }catch (Exception e){
+ String errorMsg = StrUtil.format("script loading error for node[{}]", nodeId);
+ throw new ScriptLoadException(errorMsg);
+ }
+ }
+
+ @Override
+ public void execute(String nodeId, int slotIndex) {
+ List errorList = new ArrayList<>();
+ try{
+ Slot slot = DataBus.getSlot(slotIndex);
+ DefaultContext context = new DefaultContext();
+ context.put("slot", slot);
+ expressRunner.executeByExpressName(nodeId, context, errorList, true, false, null);
+ }catch (Exception e){
+ for (String scriptErrorMsg : errorList){
+ log.error("\n{}", scriptErrorMsg);
+ }
+ String errorMsg = StrUtil.format("script execute error for node[{}]", nodeId);
+ throw new ScriptExecuteException(errorMsg);
+ }
+ }
+}
diff --git a/liteflow-script-qlexpress/src/main/resources/com.yomahub.liteflow.script.ScriptExecutor b/liteflow-script-qlexpress/src/main/resources/com.yomahub.liteflow.script.ScriptExecutor
new file mode 100644
index 000000000..e69de29bb
diff --git a/pom.xml b/pom.xml
index 4ed275f5b..73ca42d5a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,6 +56,8 @@
2.12.1
5.1.0
0.10
+ 3.2.0
+ 3.0.8
@@ -150,6 +152,17 @@
zkclient
${zkclient.version}
+
+
+ com.alibaba
+ QLExpress
+ ${qlexpress.version}
+
+
+ org.codehaus.groovy
+ groovy-all
+ ${groovy.version}
+
@@ -229,6 +242,8 @@
liteflow-core
liteflow-spring-boot-starter
+ liteflow-script-qlexpress
+ liteflow-script-common