feature #I5CW7I 【版本特性】构造全新的EL规则表达式

This commit is contained in:
everywhere.z
2022-06-24 15:01:55 +08:00
parent 90b1336737
commit fa43d4375b
36 changed files with 897 additions and 49 deletions

View File

@@ -68,6 +68,7 @@ public class LiteFlowChainELBuilder {
expressRunner.addFunctionAndClassMethod("to", Object.class, new ToOperator());
expressRunner.addFunctionAndClassMethod("tag", Object.class, new TagOperator());
expressRunner.addFunctionAndClassMethod("any", Object.class, new AnyOperator());
expressRunner.addFunctionAndClassMethod("id", Object.class, new IdOperator());
expressRunner.addFunctionAndClassMethod("ignoreError", Object.class, new IgnoreErrorOperator());
expressRunner.addFunctionAndClassMethod("threadPool", Object.class, new ThreadPoolOperator());
}
@@ -90,7 +91,7 @@ public class LiteFlowChainELBuilder {
//往上下文里放入所有的node使得el表达式可以直接引用到nodeId
DefaultContext<String, Object> context = new DefaultContext<>();
FlowBus.getNodeMap().keySet().forEach(nodeId -> context.put(nodeId, FlowBus.copyNode(nodeId)));
Condition condition = (Condition) expressRunner.execute(elStr, context, errorList, false, false);
Condition condition = (Condition) expressRunner.execute(elStr, context, errorList, false, true);
//从condition的第一层嵌套结构里拿出Pre和Finally节点
//为什么只寻找第一层,而不往下寻找了呢?

View File

@@ -24,7 +24,7 @@ public class ToOperator extends Operator {
throw new Exception();
}
if (objects.length != 2){
if (objects.length <= 2){
LOG.error("parameter error");
throw new Exception();
}

View File

@@ -21,6 +21,7 @@ import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.flow.element.Chain;
import com.yomahub.liteflow.flow.element.Node;
import com.yomahub.liteflow.parser.*;
import com.yomahub.liteflow.parser.el.*;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.property.LiteflowConfigGetter;
import com.yomahub.liteflow.slot.DataBus;
@@ -196,6 +197,12 @@ public class FlowExecutor {
return new LocalJsonFlowParser();
case TYPE_YML:
return new LocalYmlFlowParser();
case TYPE_EL_XML:
return new LocalXmlFlowELParser();
case TYPE_EL_JSON:
return new LocalJsonFlowELParser();
case TYPE_EL_YML:
return new LocalYmlFlowELParser();
default:
}
} else if (isClassConfig(path)) {
@@ -208,6 +215,12 @@ public class FlowExecutor {
return (JsonFlowParser) ContextAwareHolder.loadContextAware().registerBean(c);
case TYPE_YML:
return (YmlFlowParser) ContextAwareHolder.loadContextAware().registerBean(c);
case TYPE_EL_XML:
return (XmlFlowELParser) ContextAwareHolder.loadContextAware().registerBean(c);
case TYPE_EL_JSON:
return (JsonFlowELParser) ContextAwareHolder.loadContextAware().registerBean(c);
case TYPE_EL_YML:
return (YmlFlowELParser) ContextAwareHolder.loadContextAware().registerBean(c);
default:
}
} else if (isZKConfig(path)) {
@@ -219,6 +232,12 @@ public class FlowExecutor {
return new ZookeeperJsonFlowParser(liteflowConfig.getZkNode());
case TYPE_YML:
return new ZookeeperYmlFlowParser(liteflowConfig.getZkNode());
case TYPE_EL_XML:
return new ZookeeperXmlFlowELParser(liteflowConfig.getZkNode());
case TYPE_EL_JSON:
return new ZookeeperJsonFlowELParser(liteflowConfig.getZkNode());
case TYPE_EL_YML:
return new ZookeeperYmlFlowELParser(liteflowConfig.getZkNode());
default:
}
}
@@ -232,7 +251,10 @@ public class FlowExecutor {
private boolean isLocalConfig(String path) {
return ReUtil.isMatch(LOCAL_XML_CONFIG_REGEX, path)
|| ReUtil.isMatch(LOCAL_JSON_CONFIG_REGEX, path)
|| ReUtil.isMatch(LOCAL_YML_CONFIG_REGEX, path);
|| ReUtil.isMatch(LOCAL_YML_CONFIG_REGEX, path)
|| ReUtil.isMatch(LOCAL_EL_XML_CONFIG_REGEX, path)
|| ReUtil.isMatch(LOCAL_EL_JSON_CONFIG_REGEX, path)
|| ReUtil.isMatch(LOCAL_EL_YML_CONFIG_REGEX, path);
}
/**
@@ -268,7 +290,6 @@ public class FlowExecutor {
} else if (isClassConfig(path)) {
//其实整个这个判断块代码可以不要因为如果是自定义配置源的话标准写法也要在前面加xml:/json:/yml:这种
//但是这块可能是考虑到有些人忘加了,所以再来判断下。如果写了标准的话,是不会走到这块来的
//不过el形式的已经不支持这块了需要标准写法这点注意
try {
Class<?> clazz = Class.forName(path);
if (ClassXmlFlowParser.class.isAssignableFrom(clazz)) {
@@ -277,6 +298,12 @@ public class FlowExecutor {
return FlowParserTypeEnum.TYPE_JSON;
} else if (ClassYmlFlowParser.class.isAssignableFrom(clazz)) {
return FlowParserTypeEnum.TYPE_YML;
} else if (ClassXmlFlowELParser.class.isAssignableFrom(clazz)) {
return FlowParserTypeEnum.TYPE_EL_XML;
} else if (ClassJsonFlowELParser.class.isAssignableFrom(clazz)) {
return FlowParserTypeEnum.TYPE_EL_JSON;
} else if (ClassYmlFlowELParser.class.isAssignableFrom(clazz)) {
return FlowParserTypeEnum.TYPE_EL_YML;
}
} catch (ClassNotFoundException e) {
LOG.error(e.getMessage());

View File

@@ -45,7 +45,7 @@ public abstract class Condition implements Executable{
@Override
public String getExecuteName() {
return this.getExecuteType().name();
return this.id;
}
public List<Executable> getExecutableList() {

View File

@@ -145,7 +145,7 @@ public class WhenCondition extends Condition {
//循环判断CompletableFuture的返回值如果异步执行失败则抛出相应的业务异常
for(WhenFutureObj whenFutureObj : allCompletableWhenFutureObjList){
if (!whenFutureObj.isSuccess()){
LOG.info(StrUtil.format("requestId [{}] when-executor[{}] execute failed. errorResume [false].", whenFutureObj.getExecutorName(), slot.getRequestId()));
LOG.info(StrUtil.format("requestId [{}] when-executor[{}] execute failed. errorResume [false].",slot.getRequestId(), whenFutureObj.getExecutorName()));
throw whenFutureObj.getEx();
}
}

View File

@@ -0,0 +1,20 @@
package com.yomahub.liteflow.parser.el;
import com.yomahub.liteflow.parser.JsonFlowParser;
import java.util.List;
/**
* 基于自定义的json方式EL表达式解析器
* @author Bryan.Zhang
* @since 2.8.0
*/
public abstract class ClassJsonFlowELParser extends JsonFlowParser {
@Override
public void parseMain(List<String> pathList) throws Exception {
String content = parseCustom();
parse(content);
}
public abstract String parseCustom();
}

View File

@@ -0,0 +1,18 @@
package com.yomahub.liteflow.parser.el;
import java.util.List;
/**
* 基于自定义的xml方式EL表达式解析器
* @author Bryan.Zhang
* @since 2.8.0
*/
public abstract class ClassXmlFlowELParser extends XmlFlowELParser{
@Override
public void parseMain(List<String> pathList) throws Exception {
String content = parseCustom();
parse(content);
}
public abstract String parseCustom();
}

View File

@@ -0,0 +1,18 @@
package com.yomahub.liteflow.parser.el;
import java.util.List;
/**
* 基于自定义的yml方式EL表达式解析器
* @author Bryan.Zhang
* @since 2.8.0
*/
public abstract class ClassYmlFlowELParser extends YmlFlowELParser {
@Override
public void parseMain(List<String> pathList) throws Exception {
String content = parseCustom();
parse(content);
}
public abstract String parseCustom();
}

View File

@@ -0,0 +1,130 @@
package com.yomahub.liteflow.parser.el;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
import com.yomahub.liteflow.builder.prop.NodePropBean;
import com.yomahub.liteflow.exception.ChainDuplicateException;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.parser.BaseFlowParser;
import com.yomahub.liteflow.spi.holder.ContextCmpInitHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import static com.yomahub.liteflow.common.ChainConstant.*;
/**
* JSON形式的EL表达式解析抽象引擎
* @author Bryan.Zhang
* @since 2.8.0
*/
public abstract class JsonFlowELParser extends BaseFlowParser {
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
private final Set<String> CHAIN_NAME_SET = new CopyOnWriteArraySet<>();
public void parse(String content) throws Exception {
parse(ListUtil.toList(content));
}
@Override
public void parse(List<String> contentList) throws Exception {
if (CollectionUtil.isEmpty(contentList)) {
return;
}
List<JSONObject> jsonObjectList = ListUtil.toList();
for (String content : contentList) {
//把字符串原生转换为json对象如果不加第二个参数OrderedField会无序
JSONObject flowJsonObject = JSONObject.parseObject(content, Feature.OrderedField);
jsonObjectList.add(flowJsonObject);
}
parseJsonObject(jsonObjectList);
}
//json格式解析过程
public void parseJsonObject(List<JSONObject> flowJsonObjectList) throws Exception {
//在相应的环境下进行节点的初始化工作
//在spring体系下会获得spring扫描后的节点接入元数据
//在非spring体系下是一个空实现等于不做此步骤
ContextCmpInitHolder.loadContextCmpInit().initCmp();
//先在元数据里放上chain
//先放有一个好处可以在parse的时候先映射到FlowBus的chainMap然后再去解析
//这样就不用去像之前的版本那样回归调用
//同时也解决了不能循环依赖的问题
flowJsonObjectList.forEach(jsonObject -> {
// 解析chain节点
JSONArray chainArray = jsonObject.getJSONObject(FLOW).getJSONArray(CHAIN);
//先在元数据里放上chain
chainArray.forEach(o -> {
JSONObject innerJsonObject = (JSONObject) o;
//校验加载的 chainName 是否有重复的
//TODO 这里是否有个问题当混合格式加载的时候2个同名的Chain在不同的文件里就不行了
String chainName = innerJsonObject.getString(NAME);
if (!CHAIN_NAME_SET.add(chainName)) {
throw new ChainDuplicateException(String.format("[chain name duplicate] chainName=%s", chainName));
}
FlowBus.addChain(innerJsonObject.getString(NAME));
});
});
// 清空
CHAIN_NAME_SET.clear();
for (JSONObject flowJsonObject : flowJsonObjectList) {
// 当存在<nodes>节点定义时解析node节点
if (flowJsonObject.getJSONObject(FLOW).containsKey(NODES)) {
JSONArray nodeArrayList = flowJsonObject.getJSONObject(FLOW).getJSONObject(NODES).getJSONArray(NODE);
String id, name, clazz, script, type, file;
for (int i = 0; i < nodeArrayList.size(); i++) {
JSONObject nodeObject = nodeArrayList.getJSONObject(i);
id = nodeObject.getString(ID);
name = nodeObject.getString(NAME);
clazz = nodeObject.getString(_CLASS);
type = nodeObject.getString(TYPE);
script = nodeObject.getString(VALUE);
file = nodeObject.getString(FILE);
// 构建 node
NodePropBean nodePropBean = new NodePropBean()
.setId(id)
.setName(name)
.setClazz(clazz)
.setScript(script)
.setType(type)
.setFile(file);
buildNode(nodePropBean);
}
}
//解析每一个chain
JSONArray chainArray = flowJsonObject.getJSONObject(FLOW).getJSONArray(CHAIN);
chainArray.forEach(o -> {
JSONObject jsonObject = (JSONObject) o;
parseOneChain(jsonObject);
});
}
}
/**
* 解析一个chain的过程
*/
private void parseOneChain(JSONObject chainObject) {
//构建chainBuilder
String chainName = chainObject.getString(NAME);
String el = chainObject.getString(VALUE);
LiteFlowChainELBuilder chainELBuilder = LiteFlowChainELBuilder.createChain().setChainName(chainName);
chainELBuilder.setEL(el).build();
}
}

View File

@@ -0,0 +1,19 @@
package com.yomahub.liteflow.parser.el;
import com.yomahub.liteflow.spi.holder.PathContentParserHolder;
import java.util.List;
/**
* 基于本地的json方式EL表达式解析器
* @author Bryan.Zhang
* @since 2.8.0
*/
public class LocalJsonFlowELParser extends JsonFlowELParser {
@Override
public void parseMain(List<String> pathList) throws Exception {
List<String> contentList = PathContentParserHolder.loadContextAware().parseContent(pathList);
parse(contentList);
}
}

View File

@@ -0,0 +1,18 @@
package com.yomahub.liteflow.parser.el;
import com.yomahub.liteflow.spi.holder.PathContentParserHolder;
import java.util.List;
/**
* 基于本地的xml方式EL表达式解析器
* @author Bryan.Zhang
* @since 2.8.0
*/
public class LocalXmlFlowELParser extends XmlFlowELParser{
@Override
public void parseMain(List<String> pathList) throws Exception {
List<String> contentList = PathContentParserHolder.loadContextAware().parseContent(pathList);
parse(contentList);
}
}

View File

@@ -0,0 +1,20 @@
package com.yomahub.liteflow.parser.el;
import com.yomahub.liteflow.spi.holder.PathContentParserHolder;
import java.util.List;
/**
* 基于本地的yml方式EL表达式解析器
* @author Bryan.Zhang
* @since 2.8.0
*/
public class LocalYmlFlowELParser extends YmlFlowELParser {
@Override
public void parseMain(List<String> pathList) throws Exception {
List<String> contentList = PathContentParserHolder.loadContextAware().parseContent(pathList);
parse(contentList);
}
}

View File

@@ -3,10 +3,8 @@ package com.yomahub.liteflow.parser.el;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import com.yomahub.liteflow.builder.LiteFlowChainBuilder;
import com.yomahub.liteflow.builder.prop.ChainPropBean;
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
import com.yomahub.liteflow.builder.prop.NodePropBean;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.exception.ChainDuplicateException;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.parser.BaseFlowParser;
@@ -18,22 +16,20 @@ import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import static com.yomahub.liteflow.common.ChainConstant.*;
import static com.yomahub.liteflow.common.ChainConstant.THREAD_EXECUTOR_CLASS;
/**
* EL表达引擎Xml形式的解析抽象引擎
* Xml形式的EL表达式解析抽象引擎
* @author Bryan.Zhang
* @since 2.8.0
*/
public abstract class ELXmlFlowParser extends BaseFlowParser {
public abstract class XmlFlowELParser extends BaseFlowParser {
private final Logger LOG = LoggerFactory.getLogger(XmlFlowParser.class);
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
private final Set<String> CHAIN_NAME_SET = new CopyOnWriteArraySet<>();
@@ -122,36 +118,10 @@ public abstract class ELXmlFlowParser extends BaseFlowParser {
* 解析一个chain的过程
*/
private void parseOneChain(Element e) {
String condValueStr;
String group;
String errorResume;
String any;
String threadExecutorClass;
ConditionTypeEnum conditionType;
//构建chainBuilder
String chainName = e.attributeValue(NAME);
LiteFlowChainBuilder chainBuilder = LiteFlowChainBuilder.createChain().setChainName(chainName);
for (Iterator<Element> it = e.elementIterator(); it.hasNext(); ) {
Element condE = it.next();
conditionType = ConditionTypeEnum.getEnumByCode(condE.getName());
condValueStr = condE.attributeValue(VALUE);
errorResume = condE.attributeValue(ERROR_RESUME);
group = condE.attributeValue(GROUP);
any = condE.attributeValue(ANY);
threadExecutorClass = condE.attributeValue(THREAD_EXECUTOR_CLASS);
ChainPropBean chainPropBean = new ChainPropBean()
.setCondValueStr(condValueStr)
.setGroup(group)
.setErrorResume(errorResume)
.setAny(any)
.setThreadExecutorClass(threadExecutorClass)
.setConditionType(conditionType);
// 构建 chain
buildChain(chainPropBean, chainBuilder);
}
String el = e.getTextTrim();
LiteFlowChainELBuilder chainELBuilder = LiteFlowChainELBuilder.createChain().setChainName(chainName);
chainELBuilder.setEL(el).build();
}
}

View File

@@ -0,0 +1,49 @@
package com.yomahub.liteflow.parser.el;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yomahub.liteflow.parser.JsonFlowParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;
import java.util.List;
import java.util.Map;
/**
* yml形式的EL表达式解析抽象引擎
* @author Bryan.Zhang
* @since 2.8.0
*/
public abstract class YmlFlowELParser extends JsonFlowELParser {
private final Logger LOG = LoggerFactory.getLogger(YmlFlowELParser.class);
@Override
public void parse(String content) throws Exception{
parse(ListUtil.toList(content));
}
@Override
public void parse(List<String> contentList) throws Exception {
if (CollectionUtil.isEmpty(contentList)) {
return;
}
List<JSONObject> jsonObjectList = ListUtil.toList();
for (String content : contentList){
JSONObject ruleObject = convertToJson(content);
jsonObjectList.add(ruleObject);
}
super.parseJsonObject(jsonObjectList);
}
protected JSONObject convertToJson(String yamlString) {
Yaml yaml= new Yaml();
Map<String, Object> map = yaml.load(yamlString);
return JSON.parseObject(JSON.toJSONString(map));
}
}

View File

@@ -0,0 +1,64 @@
package com.yomahub.liteflow.parser.el;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.exception.ParseException;
import com.yomahub.liteflow.parser.JsonFlowParser;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.retry.RetryNTimes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.MessageFormat;
import java.util.List;
/**
* 基于zk方式的json形式的解析器
* @author guodongqing
* @since 2.5.0
*/
public class ZookeeperJsonFlowELParser extends JsonFlowELParser {
private static final Logger LOG = LoggerFactory.getLogger(ZookeeperJsonFlowELParser.class);
private final String nodePath;
public ZookeeperJsonFlowELParser(String node) {
nodePath = node;
}
@Override
public void parseMain(List<String> pathList) throws Exception {
//zk不允许有多个path
String path = pathList.get(0);
CuratorFramework client = CuratorFrameworkFactory.newClient(
path,
new RetryNTimes(10, 5000)
);
client.start();
if (client.checkExists().forPath(nodePath) == null) {
client.create().creatingParentsIfNeeded().forPath(nodePath, "".getBytes());
}
String content = new String(client.getData().forPath(nodePath));
if (StrUtil.isBlank(content)) {
String error = MessageFormat.format("the node[{0}] value is empty", nodePath);
throw new ParseException(error);
}
parse(content);
final NodeCache cache = new NodeCache(client,nodePath);
cache.start();
cache.getListenable().addListener(() -> {
String content1 = new String(cache.getCurrentData().getData());
LOG.info("stating load flow config....");
parse(content1);
});
}
}

View File

@@ -0,0 +1,64 @@
package com.yomahub.liteflow.parser.el;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.exception.ParseException;
import com.yomahub.liteflow.parser.XmlFlowParser;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.retry.RetryNTimes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.MessageFormat;
import java.util.List;
/**
* 基于zk方式的xml形式EL表达式解析器
* @author Bryan.Zhang
* @since 2.8.0
*/
public class ZookeeperXmlFlowELParser extends XmlFlowELParser {
private static final Logger LOG = LoggerFactory.getLogger(ZookeeperXmlFlowELParser.class);
private final String nodePath;
public ZookeeperXmlFlowELParser(String node) {
nodePath = node;
}
@Override
public void parseMain(List<String> pathList) throws Exception {
//zk不允许有多个path
String path = pathList.get(0);
CuratorFramework client = CuratorFrameworkFactory.newClient(
path,
new RetryNTimes(10, 5000)
);
client.start();
if (client.checkExists().forPath(nodePath) == null) {
client.create().creatingParentsIfNeeded().forPath(nodePath, "".getBytes());
}
String content = new String(client.getData().forPath(nodePath));
if (StrUtil.isBlank(content)) {
String error = MessageFormat.format("the node[{0}] value is empty", nodePath);
throw new ParseException(error);
}
parse(content);
final NodeCache cache = new NodeCache(client,nodePath);
cache.start();
cache.getListenable().addListener(() -> {
String content1 = new String(cache.getCurrentData().getData());
LOG.info("stating load flow config....");
parse(content1);
});
}
}

View File

@@ -0,0 +1,68 @@
package com.yomahub.liteflow.parser.el;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.yomahub.liteflow.exception.ParseException;
import com.yomahub.liteflow.parser.YmlFlowParser;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.retry.RetryNTimes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.MessageFormat;
import java.util.List;
/**
* 基于zk方式的yml形式EL表达式解析器
* @author Bryan.Zhang
* @since 2.8.0
*/
public class ZookeeperYmlFlowELParser extends YmlFlowELParser {
private static final Logger LOG = LoggerFactory.getLogger(ZookeeperYmlFlowELParser.class);
private final String nodePath;
public ZookeeperYmlFlowELParser(String node) {
nodePath = node;
}
@Override
public void parseMain(List<String> pathList) throws Exception {
//zk不允许有多个path
String path = pathList.get(0);
CuratorFramework client = CuratorFrameworkFactory.newClient(
path,
new RetryNTimes(10, 5000)
);
client.start();
if (client.checkExists().forPath(nodePath) == null) {
client.create().creatingParentsIfNeeded().forPath(nodePath, "".getBytes());
}
String content = new String(client.getData().forPath(nodePath));
if (StrUtil.isBlank(content)) {
String error = MessageFormat.format("the node[{0}] value is empty", nodePath);
throw new ParseException(error);
}
JSONObject ruleObject = convertToJson(content);
parse(ruleObject.toJSONString());
final NodeCache cache = new NodeCache(client,nodePath);
cache.start();
cache.getListenable().addListener(() -> {
String content1 = new String(cache.getCurrentData().getData());
LOG.info("stating load flow config....");
JSONObject ruleObject1 = convertToJson(content1);
parse(ruleObject1.toJSONString());
});
}
}

View File

@@ -15,9 +15,8 @@ import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
/**
* springboot环境最普通的例子测试
* springboot环境EL常规的例子测试
* @author Bryan.Zhang
* @since 2.6.4
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/base/application.properties")
@@ -29,10 +28,32 @@ public class BaseELSpringbootTest extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
//最简单的情况
@Test
public void testBase() throws Exception{
public void testBase1() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
Assert.assertTrue(response.isSuccess());
}
//switch节点最简单的测试用例
@Test
public void testBase2() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
Assert.assertTrue(response.isSuccess());
}
//then,when,switch混用的稍微复杂点的用例,switch跳到一个then上
@Test
public void testBase3() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
Assert.assertTrue(response.isSuccess());
}
//一个非常复杂的例子可以看base目录下的img.png这个图示
@Test
public void testBase4() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
Assert.assertTrue(response.isSuccess());
}
}

View File

@@ -15,7 +15,7 @@ public class DCmp extends NodeComponent {
@Override
public void process() {
System.out.println("CCmp executed!");
System.out.println("DCmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeSwitchComponent;
import org.springframework.stereotype.Component;
@Component("e")
public class ESwitchCmp extends NodeSwitchComponent {
@Override
public String processCond() throws Exception {
return "d";
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("f")
public class FCmp extends NodeComponent {
@Override
public void process() {
System.out.println("FCmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeSwitchComponent;
import org.springframework.stereotype.Component;
@Component("g")
public class GSwitchCmp extends NodeSwitchComponent {
@Override
public String processCond() throws Exception {
return "then_1001";
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("h")
public class HCmp extends NodeComponent {
@Override
public void process() {
System.out.println("HCmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("i")
public class ICmp extends NodeComponent {
@Override
public void process() {
System.out.println("ICmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("j")
public class JCmp extends NodeComponent {
@Override
public void process() {
System.out.println("JCmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("k")
public class KCmp extends NodeComponent {
@Override
public void process() {
System.out.println("KCmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("m")
public class MCmp extends NodeComponent {
@Override
public void process() {
System.out.println("MCmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("n")
public class NCmp extends NodeComponent {
@Override
public void process() {
System.out.println("NCmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("p")
public class PCmp extends NodeComponent {
@Override
public void process() {
System.out.println("PCmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("q")
public class QCmp extends NodeComponent {
@Override
public void process() {
System.out.println("QCmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("r")
public class RCmp extends NodeComponent {
@Override
public void process() {
System.out.println("RCmp executed!");
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeSwitchComponent;
import org.springframework.stereotype.Component;
@Component("x")
public class XSwitchCmp extends NodeSwitchComponent {
@Override
public String processCond() throws Exception {
return "w01";
}
}

View File

@@ -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.base.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("z")
public class ZCmp extends NodeComponent {
@Override
public void process() {
System.out.println("ZCmp executed!");
}
}

View File

@@ -1,7 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain1">
<then value="a,b"/>
<when value="c,d"/>
THEN(a,b,WHEN(c,d))
</chain>
<chain name="chain2">
THEN(
a,b,
SWITCH(e).to(d,f)
)
</chain>
<chain name="chain3">
THEN(
a,
WHEN(
c,
SWITCH(g).to(b, d, THEN(h,i).id("then_1001"))
)
)
</chain>
<chain name="chain4">
THEN(
a,b,
WHEN(
THEN(c, WHEN(j,k)),
d,
THEN(h, i)
),
SWITCH(x).to(
m,
n,
WHEN(q, THEN(p, r)).id("w01")
),
z
)
</chain>
</flow>

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="./logs" />
<!--控制台日志-->
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<!--这里替换成AspectLogbackEncoder-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="info">
<appender-ref ref="Console" />
</root>
</configuration>