feature #I4GS07 代码动态组件装配的特性

enhancement #I4QWJK 重构parser逻辑,解决的代码冗余问题
feature #I4QWH7 支持循环依赖
enhancement #I4CNO1 不使用spring无法使用
This commit is contained in:
bryan31
2022-01-14 20:20:46 +08:00
parent 3642c9ed59
commit e3a56242f9
16 changed files with 391 additions and 324 deletions

View File

@@ -1,10 +1,12 @@
package com.yomahub.liteflow.builder;
import com.yomahub.liteflow.entity.flow.Chain;
import com.yomahub.liteflow.entity.flow.Condition;
import cn.hutool.core.collection.CollectionUtil;
import com.yomahub.liteflow.entity.flow.*;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.flow.FlowBus;
import java.util.ArrayList;
import java.util.List;
/**
* Chain基于代码形式的组装器
@@ -13,7 +15,7 @@ import java.util.ArrayList;
*/
public class LiteFlowChainBuilder {
private final Chain chain;
private Chain chain;
public static LiteFlowChainBuilder createChain(){
return new LiteFlowChainBuilder();
@@ -21,20 +23,61 @@ public class LiteFlowChainBuilder {
public LiteFlowChainBuilder(){
chain = new Chain();
chain.setConditionList(new ArrayList<>());
}
public LiteFlowChainBuilder setChainName(String chainName){
this.chain.setChainName(chainName);
if (FlowBus.containChain(chainName)){
this.chain = FlowBus.getChain(chainName);
}else{
this.chain.setChainName(chainName);
}
return this;
}
public LiteFlowChainBuilder setCondition(Condition condition){
this.chain.getConditionList().add(condition);
//这里把condition组装进conditionList
buildConditions(condition);
return this;
}
public void build(){
FlowBus.addChain(this.chain);
}
private void buildConditions(Condition condition) {
//这里进行合并逻辑
//对于then来说相邻的2个then会合并成一个condition
//对于when来说相同组的when会合并成一个condition不同组的when还是会拆开
if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_PRE)) {
this.chain.getConditionList().add(new PreCondition(condition));
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_THEN)) {
if (this.chain.getConditionList().size() >= 1 &&
CollectionUtil.getLast(this.chain.getConditionList()) instanceof ThenCondition) {
CollectionUtil.getLast(this.chain.getConditionList()).getNodeList().addAll(condition.getNodeList());
} else {
this.chain.getConditionList().add(new ThenCondition(condition));
}
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_WHEN)) {
if (this.chain.getConditionList().size() > 1 &&
CollectionUtil.getLast(this.chain.getConditionList()) instanceof WhenCondition &&
CollectionUtil.getLast(this.chain.getConditionList()).getGroup().equals(condition.getGroup())) {
CollectionUtil.getLast(this.chain.getConditionList()).getNodeList().addAll(condition.getNodeList());
} else {
this.chain.getConditionList().add(new WhenCondition(condition));
}
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY)) {
this.chain.getConditionList().add(new FinallyCondition(condition));
}
//每一次build之后对conditionList进行排序pre最前面finally最后
//这里为什么要排序因为在声明的时候哪怕有人不把pre放最前finally放最后但最终也要确保是正确的顺序
CollectionUtil.sort(this.chain.getConditionList(), (o1, o2) -> {
if (o1.getConditionType().equals(ConditionTypeEnum.TYPE_PRE) || o2.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY)){
return -1;
} else if (o2.getConditionType().equals(ConditionTypeEnum.TYPE_PRE) || o1.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY)){
return 1;
}
return 0;
});
}
}

View File

@@ -22,6 +22,10 @@ public class LiteFlowConditionBuilder {
protected Condition condition;
public static LiteFlowConditionBuilder createCondition(ConditionTypeEnum conditionType){
return new LiteFlowConditionBuilder(conditionType);
}
public static LiteFlowConditionBuilder createThenCondition(){
return new LiteFlowConditionBuilder(ConditionTypeEnum.TYPE_THEN);
}
@@ -40,7 +44,7 @@ public class LiteFlowConditionBuilder {
public LiteFlowConditionBuilder(ConditionTypeEnum conditionType){
this.condition = new Condition();
this.condition.setConditionType(conditionType.getType());
this.condition.setConditionType(conditionType);
this.condition.setNodeList(new ArrayList<>());
}

View File

@@ -1,14 +1,21 @@
package com.yomahub.liteflow.builder;
import com.yomahub.liteflow.entity.flow.Chain;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.entity.flow.Node;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.exception.NodeBuildException;
import com.yomahub.liteflow.flow.FlowBus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LiteFlowNodeBuilder {
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
private final Node node;
public static LiteFlowNodeBuilder createNode(){
public static LiteFlowNodeBuilder createNode() {
return new LiteFlowNodeBuilder();
}
@@ -16,19 +23,52 @@ public class LiteFlowNodeBuilder {
this.node = new Node();
}
public LiteFlowNodeBuilder setId(String nodeId){
public LiteFlowNodeBuilder setId(String nodeId) {
this.node.setId(nodeId);
return this;
}
public LiteFlowNodeBuilder setName(String name){
public LiteFlowNodeBuilder setName(String name) {
this.node.setName(name);
return this;
}
public LiteFlowNodeBuilder setType(NodeTypeEnum type){
public LiteFlowNodeBuilder setClazz(String clazz) {
this.node.setClazz(clazz);
return this;
}
public LiteFlowNodeBuilder setType(NodeTypeEnum type) {
this.node.setType(type);
return this;
}
public LiteFlowNodeBuilder setScript(String script) {
this.node.setScript(script);
return this;
}
public LiteFlowNodeBuilder setFile(String filePath) {
if (StrUtil.isBlank(filePath)){
return this;
}
String script = ResourceUtil.readUtf8Str(StrUtil.format("classpath: {}", filePath));
return setScript(script);
}
public void build() {
try {
if (this.node.getType().equals(NodeTypeEnum.COMMON)) {
FlowBus.addCommonNode(this.node.getId(), this.node.getName(), this.node.getClazz());
} else if (this.node.getType().equals(NodeTypeEnum.SCRIPT)){
FlowBus.addCommonScriptNode(this.node.getId(), this.node.getName(), this.node.getScript());
} else if (this.node.getType().equals(NodeTypeEnum.COND_SCRIPT)){
FlowBus.addCondScriptNode(this.node.getId(), this.node.getName(), this.node.getScript());
}
} catch (Exception e) {
String errMsg = StrUtil.format("An exception occurred while building the node[{}]", this.node.getId());
LOG.error(errMsg, e);
throw new NodeBuildException(errMsg);
}
}
}

View File

@@ -1,5 +1,7 @@
package com.yomahub.liteflow.builder;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.common.LocalDefaultFlowConstant;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
/**
@@ -14,18 +16,36 @@ public class LiteFlowWhenConditionBuilder extends LiteFlowConditionBuilder{
super(conditionType);
}
public LiteFlowConditionBuilder setErrorResume(boolean errorResume){
public LiteFlowWhenConditionBuilder setErrorResume(boolean errorResume){
this.condition.setErrorResume(errorResume);
return this;
}
public LiteFlowConditionBuilder setGroup(String group){
this.condition.setGroup(group);
public LiteFlowWhenConditionBuilder setErrorResume(String errorResume){
if (StrUtil.isBlank(errorResume)){
return this;
}
return setErrorResume(Boolean.parseBoolean(errorResume));
}
public LiteFlowWhenConditionBuilder setGroup(String group){
if (StrUtil.isBlank(group)){
this.condition.setGroup(LocalDefaultFlowConstant.DEFAULT);
}else{
this.condition.setGroup(group);
}
return this;
}
public LiteFlowConditionBuilder setAny(boolean any){
public LiteFlowWhenConditionBuilder setAny(boolean any){
this.condition.setAny(any);
return this;
}
public LiteFlowWhenConditionBuilder setAny(String any){
if (StrUtil.isBlank(any)){
return this;
}
return setAny(Boolean.parseBoolean(any));
}
}

View File

@@ -40,12 +40,14 @@ public class Chain implements Executable {
private String chainName;
private List<Condition> conditionList;
public Chain(){
private List<Condition> conditionList = new ArrayList<>();
public Chain(String chainName){
this.chainName = chainName;
}
public Chain(){}
public Chain(String chainName, List<Condition> conditionList) {
this.chainName = chainName;
this.conditionList = conditionList;
@@ -94,7 +96,7 @@ public class Chain implements Executable {
public void executeFinally(Integer slotIndex) throws Exception {
//先把finally的节点过滤出来
List<Condition> finallyConditionList = conditionList.stream().filter(condition ->
condition.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY.getType())).collect(Collectors.toList());
condition.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY)).collect(Collectors.toList());
for (Condition finallyCondition : finallyConditionList){
for(Executable executableItem : finallyCondition.getNodeList()){
executableItem.execute(slotIndex);

View File

@@ -8,6 +8,7 @@
package com.yomahub.liteflow.entity.flow;
import com.yomahub.liteflow.common.LocalDefaultFlowConstant;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import java.util.List;
@@ -18,7 +19,7 @@ import java.util.List;
public class Condition {
//condition 类型 参数:ConditionTypeEnum 包含:then when
private String conditionType;
private ConditionTypeEnum conditionType;
private List<Executable> nodeList;
@@ -61,11 +62,11 @@ public class Condition {
this.group = group;
}
public String getConditionType() {
public ConditionTypeEnum getConditionType() {
return conditionType;
}
public void setConditionType(String conditionType) {
public void setConditionType(ConditionTypeEnum conditionType) {
this.conditionType = conditionType;
}

View File

@@ -37,7 +37,7 @@ public class Node implements Executable,Cloneable{
private String name;
private String tag;
private String clazz;
private NodeTypeEnum type;
@@ -45,6 +45,8 @@ public class Node implements Executable,Cloneable{
private NodeComponent instance;
private String tag;
private final Map<String, Executable> condNodeMap = new HashMap<>();
public Node(){
@@ -56,6 +58,7 @@ public class Node implements Executable,Cloneable{
this.name = instance.getName();
this.instance = instance;
this.type = instance.getType();
this.clazz = instance.getClass().getName();
}
public String getId() {
@@ -204,4 +207,12 @@ public class Node implements Executable,Cloneable{
public void setScript(String script) {
this.script = script;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
}

View File

@@ -29,4 +29,13 @@ public enum ConditionTypeEnum {
public void setName(String name) {
this.name = name;
}
public static ConditionTypeEnum getEnumByCode(String code) {
for (ConditionTypeEnum e : ConditionTypeEnum.values()) {
if (e.getType().equals(code)) {
return e;
}
}
return null;
}
}

View File

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

View File

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

View File

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

View File

@@ -18,6 +18,7 @@ import com.yomahub.liteflow.core.ScriptComponent;
import com.yomahub.liteflow.core.ScriptCondComponent;
import com.yomahub.liteflow.entity.data.DataBus;
import com.yomahub.liteflow.entity.flow.Chain;
import com.yomahub.liteflow.entity.flow.Condition;
import com.yomahub.liteflow.entity.flow.Node;
import com.yomahub.liteflow.enums.FlowParserTypeEnum;
import com.yomahub.liteflow.enums.NodeTypeEnum;
@@ -38,6 +39,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.util.SerializationUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@@ -60,7 +62,11 @@ public class FlowBus {
}
public static void addChain(Chain chain) {
chainMap.put(chain.getChainName(), chain);
if (chainMap.containsKey(chain.getChainName()) && CollectionUtil.isEmpty(chain.getConditionList())){
chainMap.get(chain.getChainName()).setConditionList(chain.getConditionList());
}else{
chainMap.put(chain.getChainName(), chain);
}
}
public static boolean containChain(String chainId) {

View File

@@ -27,43 +27,6 @@ public abstract class FlowParser {
public abstract void parse(List<String> contentList) throws Exception;
protected void buildConditions(List<Condition> conditionList, Condition condition) {
//这里进行合并逻辑
//对于then来说相邻的2个then会合并成一个condition
//对于when来说相同组的when会合并成一个condition不同组的when还是会拆开
if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_PRE.getType())) {
conditionList.add(new PreCondition(condition));
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_THEN.getType())) {
if (conditionList.size() >= 1 &&
CollectionUtil.getLast(conditionList) instanceof ThenCondition) {
CollectionUtil.getLast(conditionList).getNodeList().addAll(condition.getNodeList());
} else {
conditionList.add(new ThenCondition(condition));
}
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_WHEN.getType())) {
if (conditionList.size() > 1 &&
CollectionUtil.getLast(conditionList) instanceof WhenCondition &&
CollectionUtil.getLast(conditionList).getGroup().equals(condition.getGroup())) {
CollectionUtil.getLast(conditionList).getNodeList().addAll(condition.getNodeList());
} else {
conditionList.add(new WhenCondition(condition));
}
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY.getType())) {
conditionList.add(new FinallyCondition(condition));
}
//每一次build之后对conditionList进行排序pre最前面finally最后
//这里为什么要排序因为在声明的时候哪怕有人不把pre放最前finally放最后但最终也要确保是正确的顺序
CollectionUtil.sort(conditionList, (o1, o2) -> {
if (o1.getConditionType().equals(ConditionTypeEnum.TYPE_PRE.getType()) || o2.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY.getType())){
return -1;
} else if (o2.getConditionType().equals(ConditionTypeEnum.TYPE_PRE.getType()) || o1.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY.getType())){
return 1;
}
return 0;
});
}
/**
* 根据配置的ruleSource查找匹配的资源
*/

View File

@@ -8,18 +8,26 @@ import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.yomahub.liteflow.builder.LiteFlowChainBuilder;
import com.yomahub.liteflow.builder.LiteFlowConditionBuilder;
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
import com.yomahub.liteflow.common.LocalDefaultFlowConstant;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.flow.*;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.exception.EmptyConditionValueException;
import com.yomahub.liteflow.exception.ExecutableItemNotFoundException;
import com.yomahub.liteflow.exception.NodeTypeNotSupportException;
import com.yomahub.liteflow.exception.NotSupportConditionException;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.spring.ComponentScanner;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.function.Consumer;
/**
* Json格式解析器
@@ -53,171 +61,120 @@ public abstract class JsonFlowParser extends FlowParser {
//json格式解析过程
public void parseJsonObject(List<JSONObject> flowJsonObjectList) throws Exception {
try {
for (Map.Entry<String, NodeComponent> componentEntry : ComponentScanner.nodeComponentMap.entrySet()) {
if (!FlowBus.containNode(componentEntry.getKey())) {
FlowBus.addSpringScanNode(componentEntry.getKey(), componentEntry.getValue());
}
for (Map.Entry<String, NodeComponent> componentEntry : ComponentScanner.nodeComponentMap.entrySet()) {
if (!FlowBus.containNode(componentEntry.getKey())) {
FlowBus.addSpringScanNode(componentEntry.getKey(), componentEntry.getValue());
}
}
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");
file = nodeObject.getString("file");
//先在元数据里放上chain
//先放有一个好处可以在parse的时候先映射到FlowBus的chainMap然后再去解析
//这样就不用去像之前的版本那样回归调用
//同时也解决了不能循环依赖的问题
flowJsonObjectList.forEach(jsonObject -> {
// 解析chain节点
JSONArray chainArray = jsonObject.getJSONObject("flow").getJSONArray("chain");
//初始化type
if (StrUtil.isBlank(type)){
type = NodeTypeEnum.COMMON.getCode();
}
NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type);
if (ObjectUtil.isNull(nodeTypeEnum)){
throw new NodeTypeNotSupportException(StrUtil.format("type [{}] is not support", type));
}
//先在元数据里放上chain
chainArray.forEach(o -> {
JSONObject innerJsonObject = (JSONObject)o;
FlowBus.addChain(new Chain(innerJsonObject.getString("name")));
});
});
//这里区分是普通java节点还是脚本节点
//如果是脚本节点,又区分是普通脚本节点,还是条件脚本节点
if (nodeTypeEnum.equals(NodeTypeEnum.COMMON) && StrUtil.isNotBlank(clazz)){
FlowBus.addCommonNode(id, name, clazz);
}else if(nodeTypeEnum.equals(NodeTypeEnum.SCRIPT) || nodeTypeEnum.equals(NodeTypeEnum.COND_SCRIPT)){
//如果file字段不为空则优先从file里面读取脚本文本
if (StrUtil.isNotBlank(file)){
script = ResourceUtil.readUtf8Str(StrUtil.format("classpath: {}", file));
}else{
script = nodeObject.getString("value");
}
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");
//根据节点类型把脚本添加到元数据里
if (nodeTypeEnum.equals(NodeTypeEnum.SCRIPT)){
FlowBus.addCommonScriptNode(id, name, script);
}else {
FlowBus.addCondScriptNode(id, name, script);
}
}
//初始化type
if (StrUtil.isBlank(type)){
type = NodeTypeEnum.COMMON.getCode();
}
}
// 解析chain节点
JSONArray chainArray = flowJsonObject.getJSONObject("flow").getJSONArray("chain");
for (int i = 0; i < chainArray.size(); i++) {
JSONObject jsonObject = chainArray.getJSONObject(i);
parseOneChain(jsonObject, flowJsonObjectList);
//检查nodeType是不是规定的类型
NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type);
if (ObjectUtil.isNull(nodeTypeEnum)){
throw new NodeTypeNotSupportException(StrUtil.format("type [{}] is not support", type));
}
//进行node的build过程
LiteFlowNodeBuilder.createNode().setId(id)
.setName(name)
.setClazz(clazz)
.setType(nodeTypeEnum)
.setScript(script)
.setFile(file)
.build();
}
}
} catch (Exception e) {
LOG.error("JsonFlowParser parser exception", e);
throw e;
//解析每一个chain
JSONArray chainArray = flowJsonObject.getJSONObject("flow").getJSONArray("chain");
chainArray.forEach(o -> {
JSONObject jsonObject = (JSONObject)o;
parseOneChain(jsonObject);
});
}
}
/**
* 解析一个chain的过程
*/
private void parseOneChain(JSONObject chainObject, List<JSONObject> flowJsonObjectList) throws Exception {
String condArrayStr;
String[] condArray;
List<Executable> chainNodeList;
List<Condition> conditionList = new ArrayList<>();
private void parseOneChain(JSONObject chainObject){
String condValueStr;
ConditionTypeEnum conditionType;
String group;
String errorResume;
Condition condition;
String any;
//构建chainBuilder
String chainName = chainObject.getString("name");
JSONArray conditionArray = chainObject.getJSONArray("condition");
for (Object o : conditionArray) {
LiteFlowChainBuilder chainBuilder = LiteFlowChainBuilder.createChain().setChainName(chainName);
for (Object o : chainObject.getJSONArray("condition")) {
JSONObject condObject = (JSONObject) o;
String condType = condObject.getString("type");
condArrayStr = condObject.getString("value");
group = condObject.getString("group");
conditionType = ConditionTypeEnum.getEnumByCode(condObject.getString("type"));
condValueStr = condObject.getString("value");
errorResume = condObject.getString("errorResume");
group = condObject.getString("group");
any = condObject.getString("any");
if (StrUtil.isBlank(condType) || StrUtil.isBlank(condArrayStr)) {
continue;
}
if (StrUtil.isBlank(group)) {
group = LocalDefaultFlowConstant.DEFAULT;
}
if (StrUtil.isBlank(errorResume)) {
errorResume = Boolean.FALSE.toString();
}
if (StrUtil.isBlank(any)){
any = Boolean.FALSE.toString();
}
condition = new Condition();
chainNodeList = new ArrayList<>();
condArray = condArrayStr.split(",");
RegexEntity regexEntity;
String itemExpression;
RegexNodeEntity item;
//这里解析的规则优先按照node去解析再按照chain去解析
for (int i = 0; i < condArray.length; i++) {
itemExpression = condArray[i].trim();
regexEntity = RegexEntity.parse(itemExpression);
item = regexEntity.getItem();
if (FlowBus.containNode(item.getId())) {
Node node = FlowBus.copyNode(item.getId());
node.setTag(regexEntity.getItem().getTag());
chainNodeList.add(node);
//这里判断是不是条件节点条件节点会含有realItem也就是括号里的node
if (regexEntity.getRealItemArray() != null) {
for (RegexNodeEntity realItem : regexEntity.getRealItemArray()) {
if (FlowBus.containNode(realItem.getId())) {
Node condNode = FlowBus.copyNode(realItem.getId());
condNode.setTag(realItem.getTag());
node.setCondNode(condNode.getId(), condNode);
} else if (hasChain(flowJsonObjectList, realItem.getId())) {
Chain chain = FlowBus.getChain(realItem.getId());
node.setCondNode(chain.getChainName(), chain);
} else{
String errorMsg = StrUtil.format("executable node[{}] is not found!", realItem.getId());
throw new ExecutableItemNotFoundException(errorMsg);
}
}
}
} else if (hasChain(flowJsonObjectList, item.getId())) {
Chain chain = FlowBus.getChain(item.getId());
chainNodeList.add(chain);
} else {
String errorMsg = StrUtil.format("executable node[{}] is not found!", regexEntity.getItem().getId());
throw new ExecutableItemNotFoundException(errorMsg);
}
}
condition.setErrorResume(Boolean.parseBoolean(errorResume));
condition.setGroup(group);
condition.setAny(any.equals(Boolean.TRUE.toString()));
condition.setConditionType(condType);
condition.setNodeList(chainNodeList);
//这里把condition组装进conditionList根据参数有些condition要和conditionList里面的某些进行合并操作
super.buildConditions(conditionList, condition);
}
FlowBus.addChain(new Chain(chainName, conditionList));
}
if (ObjectUtil.isNull(conditionType)){
throw new NotSupportConditionException("ConditionType is not supported");
}
/**
* 判断在这个FlowBus元数据里是否含有这个chain
* 因为chain和node都是可执行器在一个规则文件上有可能是node有可能是chain
*/
private boolean hasChain(List<JSONObject> flowJsonObjectList, String chainName) throws Exception {
for (JSONObject jsonObject : flowJsonObjectList) {
JSONArray chainArray = jsonObject.getJSONObject("flow").getJSONArray("chain");
for (int i = 0; i < chainArray.size(); i++) {
JSONObject chainObject = chainArray.getJSONObject(i);
if (chainObject.getString("name").equals(chainName) && !FlowBus.containChain(chainName)) {
parseOneChain(chainObject, flowJsonObjectList);
return true;
} else if (FlowBus.containChain(chainName)) {
return true;
}
if (StrUtil.isBlank(condValueStr)) {
throw new EmptyConditionValueException("Condition value cannot be empty");
}
//如果是when类型的话有特殊化参数要设置只针对于when的
if (conditionType.equals(ConditionTypeEnum.TYPE_WHEN)){
chainBuilder.setCondition(
LiteFlowConditionBuilder.createWhenCondition()
.setErrorResume(errorResume)
.setGroup(group)
.setAny(any)
.setValue(condValueStr)
.build()
).build();
}else{
chainBuilder.setCondition(
LiteFlowConditionBuilder.createCondition(conditionType)
.setValue(condValueStr)
.build()
).build();
}
}
return false;
}
}

View File

@@ -5,17 +5,18 @@ import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.builder.LiteFlowChainBuilder;
import com.yomahub.liteflow.builder.LiteFlowConditionBuilder;
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
import com.yomahub.liteflow.common.LocalDefaultFlowConstant;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.flow.Chain;
import com.yomahub.liteflow.entity.flow.Condition;
import com.yomahub.liteflow.entity.flow.Executable;
import com.yomahub.liteflow.entity.flow.Node;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.exception.CyclicDependencyException;
import com.yomahub.liteflow.exception.ExecutableItemNotFoundException;
import com.yomahub.liteflow.exception.NodeTypeNotSupportException;
import com.yomahub.liteflow.exception.ParseException;
import com.yomahub.liteflow.exception.*;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.spring.ComponentScanner;
import org.dom4j.Document;
@@ -28,10 +29,10 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.function.Consumer;
/**
* xml形式的解析器
*
* @author Bryan.Zhang
*/
public abstract class XmlFlowParser extends FlowParser {
@@ -63,6 +64,18 @@ public abstract class XmlFlowParser extends FlowParser {
}
}
//先在元数据里放上chain
//先放有一个好处可以在parse的时候先映射到FlowBus的chainMap然后再去解析
//这样就不用去像之前的版本那样回归调用
//同时也解决了不能循环依赖的问题
documentList.forEach(document -> {
// 解析chain节点
List<Element> chainList = document.getRootElement().elements("chain");
//先在元数据里放上chain
chainList.forEach(e -> FlowBus.addChain(new Chain(e.attributeValue("name"))));
});
for (Document document : documentList) {
Element rootElement = document.getRootElement();
Element nodesElement = rootElement.element("nodes");
@@ -75,152 +88,84 @@ public abstract class XmlFlowParser extends FlowParser {
name = e.attributeValue("name");
clazz = e.attributeValue("class");
type = e.attributeValue("type");
script = e.getTextTrim();
file = e.attributeValue("file");
//初始化type
if (StrUtil.isBlank(type)){
type = NodeTypeEnum.COMMON.getCode();
}
//检查nodeType是不是规定的类型
NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type);
if (ObjectUtil.isNull(nodeTypeEnum)){
throw new NodeTypeNotSupportException(StrUtil.format("type [{}] is not support", type));
}
//这里区分是普通java节点还是脚本节点
//如果是脚本节点,又区分是普通脚本节点,还是条件脚本节点
if (nodeTypeEnum.equals(NodeTypeEnum.COMMON) && StrUtil.isNotBlank(clazz)){
FlowBus.addCommonNode(id, name, clazz);
}else if(nodeTypeEnum.equals(NodeTypeEnum.SCRIPT) || nodeTypeEnum.equals(NodeTypeEnum.COND_SCRIPT)){
//如果file字段不为空则优先从file里面读取脚本文本
if (StrUtil.isNotBlank(file)){
script = ResourceUtil.readUtf8Str(StrUtil.format("classpath: {}", file));
}else{
script = e.getTextTrim();
}
//根据节点类型把脚本添加到元数据里
if (nodeTypeEnum.equals(NodeTypeEnum.SCRIPT)){
FlowBus.addCommonScriptNode(id, name, script);
}else {
FlowBus.addCondScriptNode(id, name, script);
}
}
//进行node的build过程
LiteFlowNodeBuilder.createNode().setId(id)
.setName(name)
.setClazz(clazz)
.setType(nodeTypeEnum)
.setScript(script)
.setFile(file)
.build();
}
}
// 解析chain节点
//解析每一个chain
List<Element> chainList = rootElement.elements("chain");
for (Element e : chainList) {
parseOneChain(e, documentList);
}
chainList.forEach(this::parseOneChain);
}
}
/**
* 解析一个chain的过程
*/
private void parseOneChain(Element e, List<Document> documentList) throws Exception {
String condArrayStr;
String[] condArray;
private void parseOneChain(Element e) {
String condValueStr;
String group;
String errorResume;
String any;
Condition condition;
Element condE;
List<Executable> chainNodeList;
List<Condition> conditionList = new ArrayList<>();
ConditionTypeEnum conditionType;
//构建chainBuilder
String chainName = e.attributeValue("name");
LiteFlowChainBuilder chainBuilder = LiteFlowChainBuilder.createChain().setChainName(chainName);
for (Iterator<Element> it = e.elementIterator(); it.hasNext(); ) {
condE = it.next();
condArrayStr = condE.attributeValue("value");
Element condE = it.next();
conditionType = ConditionTypeEnum.getEnumByCode(condE.getName());
condValueStr = condE.attributeValue("value");
errorResume = condE.attributeValue("errorResume");
group = condE.attributeValue("group");
any = condE.attributeValue("any");
if (StrUtil.isBlank(condArrayStr)) {
continue;
}
if (StrUtil.isBlank(group)) {
group = LocalDefaultFlowConstant.DEFAULT;
}
if (StrUtil.isBlank(errorResume)) {
errorResume = Boolean.FALSE.toString();
}
if (StrUtil.isBlank(any)){
any = Boolean.FALSE.toString();
}
condition = new Condition();
chainNodeList = new ArrayList<>();
condArray = condArrayStr.split(",");
RegexEntity regexEntity;
String itemExpression;
RegexNodeEntity item;
//这里解析的规则优先按照node去解析再按照chain去解析
for (String s : condArray) {
itemExpression = s.trim();
regexEntity = RegexEntity.parse(itemExpression);
item = regexEntity.getItem();
if (FlowBus.containNode(item.getId())) {
Node node = FlowBus.copyNode(item.getId());
node.setTag(regexEntity.getItem().getTag());
chainNodeList.add(node);
//这里判断是不是条件节点条件节点会含有realItem也就是括号里的node
if (regexEntity.getRealItemArray() != null) {
for (RegexNodeEntity realItem : regexEntity.getRealItemArray()) {
if (FlowBus.containNode(realItem.getId())) {
Node condNode = FlowBus.copyNode(realItem.getId());
condNode.setTag(realItem.getTag());
node.setCondNode(condNode.getId(), condNode);
} else if (hasChain(documentList, realItem.getId())) {
Chain chain = FlowBus.getChain(realItem.getId());
node.setCondNode(chain.getChainName(), chain);
} else{
String errorMsg = StrUtil.format("executable node[{}] is not found!", realItem.getId());
throw new ExecutableItemNotFoundException(errorMsg);
}
}
}
} else if (hasChain(documentList, item.getId())) {
Chain chain = FlowBus.getChain(item.getId());
chainNodeList.add(chain);
} else {
String errorMsg = StrUtil.format("executable node[{}] is not found!", regexEntity.getItem().getId());
throw new ExecutableItemNotFoundException(errorMsg);
}
}
condition.setErrorResume(Boolean.parseBoolean(errorResume));
condition.setGroup(group);
condition.setAny(any.equals(Boolean.TRUE.toString()));
condition.setConditionType(condE.getName());
condition.setNodeList(chainNodeList);
//这里把condition组装进conditionList根据参数有些condition要和conditionList里面的某些进行合并操作
super.buildConditions(conditionList, condition);
}
FlowBus.addChain(new Chain(chainName, conditionList));
}
//判断在这个FlowBus元数据里是否含有这个chain
//因为chain和node都是可执行器在一个规则文件上有可能是node有可能是chain
@SuppressWarnings("unchecked")
private boolean hasChain(List<Document> documentList, String chainName) throws Exception {
try{
for (Document document : documentList) {
List<Element> chainList = document.getRootElement().elements("chain");
for (Element ce : chainList) {
String ceName = ce.attributeValue("name");
if (ceName.equals(chainName)) {
if (!FlowBus.containChain(chainName)) {
parseOneChain(ce, documentList);
}
return true;
}
}
if (ObjectUtil.isNull(conditionType)){
throw new NotSupportConditionException("ConditionType is not supported");
}
if (StrUtil.isBlank(condValueStr)) {
throw new EmptyConditionValueException("Condition value cannot be empty");
}
//如果是when类型的话有特殊化参数要设置只针对于when的
if (conditionType.equals(ConditionTypeEnum.TYPE_WHEN)){
chainBuilder.setCondition(
LiteFlowConditionBuilder.createWhenCondition()
.setErrorResume(errorResume)
.setGroup(group)
.setAny(any)
.setValue(condValueStr)
.build()
).build();
}else{
chainBuilder.setCondition(
LiteFlowConditionBuilder.createCondition(conditionType)
.setValue(condValueStr)
.build()
).build();
}
return false;
}catch (StackOverflowError e){
LOG.error("a cyclic dependency occurs in chain", e);
throw new CyclicDependencyException("a cyclic dependency occurs in chain");
}
}
}