Skip to content

Commit 913c1b9

Browse files
committed
fix flow-engine node data-struct
1 parent 772fb94 commit 913c1b9

10 files changed

Lines changed: 483 additions & 125 deletions

File tree

Lines changed: 45 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,75 @@
11
package com.codingapi.flow.manager;
22

3+
import com.codingapi.flow.exception.FlowConfigException;
34
import com.codingapi.flow.node.IFlowNode;
4-
import com.codingapi.flow.node.NodeType;
55

66
import java.util.ArrayList;
7+
import java.util.Iterator;
78
import java.util.List;
9+
import java.util.stream.Stream;
810

911
/**
10-
* TODO 节点关系管理,寻找下一节点的路径上存在bug
12+
* 流程节点关系管理器
1113
*/
1214
public class FlowNodeEdgeManager {
1315

14-
private final List<IFlowNode> nodes;
15-
16-
private final List<String> blockNodeTypes = new ArrayList<>();
17-
private final List<String> branchNodeTypes = new ArrayList<>();
16+
private final Iterator<FlowNodeState> nodes;
1817

1918
public FlowNodeEdgeManager(List<IFlowNode> nodes) {
20-
this.nodes = nodes;
21-
22-
this.blockNodeTypes.add(NodeType.CONDITION.name());
23-
this.blockNodeTypes.add(NodeType.INCLUSIVE.name());
24-
this.blockNodeTypes.add(NodeType.PARALLEL.name());
25-
26-
this.branchNodeTypes.add(NodeType.CONDITION_BRANCH.name());
27-
this.branchNodeTypes.add(NodeType.INCLUSIVE_BRANCH.name());
28-
this.branchNodeTypes.add(NodeType.PARALLEL_BRANCH.name());
19+
this.nodes = nodes.stream().map(FlowNodeState::new).iterator();
2920
}
3021

22+
/**
23+
* 获取下一节点
24+
*
25+
* @param current 当前节点
26+
* @return 下一节点列表
27+
*/
3128
public List<IFlowNode> getNextNodes(IFlowNode current) {
32-
return this.loadNextNodes(current);
29+
return this.loadNextNodes(new FlowNodeState(current), this.nodes);
3330
}
3431

35-
private List<IFlowNode> loadNextNodes(IFlowNode current) {
36-
if (isBlockNode(current)) {
37-
return current.blocks();
32+
/**
33+
* 加载下一节点
34+
* @param current 当前节点状态
35+
* @param iterator 当前遍历的节点列表
36+
* @return 下一节点列表
37+
*/
38+
private List<IFlowNode> loadNextNodes(FlowNodeState current, Iterator<FlowNodeState> iterator) {
39+
if(current.isEndNode()){
40+
return new ArrayList<>();
3841
}
39-
if (isBranchNode(current)) {
40-
List<IFlowNode> branchNodes = current.blocks();
41-
if (branchNodes != null && !branchNodes.isEmpty()) {
42-
return List.of(branchNodes.get(0));
43-
}
44-
}
45-
return this.fetchNextNode(current, this.nodes);
46-
}
47-
48-
49-
private boolean isBlockNode(IFlowNode node) {
50-
return blockNodeTypes.contains(node.getType());
51-
}
52-
53-
private boolean isBranchNode(IFlowNode node) {
54-
return branchNodeTypes.contains(node.getType());
55-
}
56-
57-
58-
private List<IFlowNode> fetchNextNode(IFlowNode current, List<IFlowNode> nodes) {
59-
List<IFlowNode> nextNodes = new ArrayList<>();
60-
boolean match = false;
61-
62-
for (int i = 0; i < nodes.size(); i++) {
63-
IFlowNode node = nodes.get(i);
64-
if (match) {
65-
nextNodes.add(node);
66-
break;
67-
}
68-
if (current.getId().equals(node.getId())) {
69-
match = true;
70-
}
71-
if (this.isBlockNode(node) || this.isBranchNode(node)) {
72-
List<IFlowNode> matchNodes = this.fetchNextNode(current, node.blocks());
73-
if (!matchNodes.isEmpty()) {
74-
nextNodes.addAll(matchNodes);
42+
while (iterator.hasNext()) {
43+
FlowNodeState node = iterator.next();
44+
if (node.equals(current)) {
45+
if (node.isBlockNode()) {
46+
return node.getBlocks();
47+
}
48+
if (node.isBranchNode()) {
49+
return node.getFirstBlocks();
50+
}
51+
if (iterator.hasNext()) {
52+
FlowNodeState next = iterator.next();
53+
return Stream.of(next.getNode()).toList();
7554
} else {
76-
if (this.hasNodeBlocks(node, current)) {
77-
nextNodes.add(nodes.get(i + 1));
78-
break;
55+
// 跳过大循环,直接进入下一节点
56+
if (this.nodes.hasNext()) {
57+
return Stream.of(this.nodes.next().getNode()).toList();
58+
}else {
59+
throw FlowConfigException.edgeConfigError(current.getName());
7960
}
8061
}
8162
}
82-
}
83-
return nextNodes;
84-
}
8563

86-
87-
private boolean hasNodeBlocks(IFlowNode node, IFlowNode current) {
88-
List<IFlowNode> blocks = node.blocks();
89-
return blocks != null && !blocks.isEmpty() && hasNodeBlocks(current, blocks);
90-
}
91-
92-
93-
private boolean hasNodeBlocks(IFlowNode current, List<IFlowNode> nodes) {
94-
for (IFlowNode node : nodes) {
95-
if (node.getId().equals(current.getId())) {
96-
return true;
97-
}
98-
if (this.isBlockNode(node) || this.isBranchNode(node)) {
99-
if (hasNodeBlocks(current, node.blocks())) {
100-
return true;
64+
if (node.isBlockNode() || node.isBranchNode()) {
65+
List<IFlowNode> nextNodes = this.loadNextNodes(current, node.getBlocks().stream().map(FlowNodeState::new).toList().iterator());
66+
if (!nextNodes.isEmpty()) {
67+
return nextNodes;
10168
}
10269
}
70+
10371
}
104-
return false;
72+
return new ArrayList<>();
10573
}
10674

10775
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.codingapi.flow.manager;
2+
3+
import com.codingapi.flow.node.IFlowNode;
4+
import com.codingapi.flow.node.NodeType;
5+
import lombok.Getter;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import java.util.stream.Stream;
10+
11+
/**
12+
* 流程节点状态
13+
*/
14+
public class FlowNodeState {
15+
16+
@Getter
17+
private final IFlowNode node;
18+
19+
private final List<String> blockNodeTypes = new ArrayList<>();
20+
private final List<String> branchNodeTypes = new ArrayList<>();
21+
22+
public FlowNodeState(IFlowNode node) {
23+
this.node = node;
24+
25+
this.blockNodeTypes.add(NodeType.CONDITION.name());
26+
this.blockNodeTypes.add(NodeType.INCLUSIVE.name());
27+
this.blockNodeTypes.add(NodeType.PARALLEL.name());
28+
29+
this.branchNodeTypes.add(NodeType.CONDITION_BRANCH.name());
30+
this.branchNodeTypes.add(NodeType.INCLUSIVE_BRANCH.name());
31+
this.branchNodeTypes.add(NodeType.PARALLEL_BRANCH.name());
32+
}
33+
34+
public boolean isEndNode(){
35+
return this.node.getType().equals(NodeType.END.name());
36+
}
37+
38+
public boolean isBlockNode() {
39+
return blockNodeTypes.contains(node.getType());
40+
}
41+
42+
public boolean isBranchNode() {
43+
return branchNodeTypes.contains(node.getType());
44+
}
45+
46+
public List<IFlowNode> getBlocks() {
47+
return this.node.blocks();
48+
}
49+
50+
@Override
51+
public boolean equals(Object obj) {
52+
if (obj instanceof FlowNodeState target) {
53+
return target.getId().equals(this.getId());
54+
}
55+
return super.equals(obj);
56+
}
57+
58+
public String getId() {
59+
return this.node.getId();
60+
}
61+
62+
63+
public String getName() {
64+
return this.node.getName();
65+
}
66+
67+
public List<IFlowNode> getFirstBlocks() {
68+
List<IFlowNode> blocks = this.node.blocks();
69+
if (blocks != null && !blocks.isEmpty()) {
70+
return Stream.of(blocks.get(0)).toList();
71+
}
72+
return new ArrayList<>();
73+
}
74+
}

flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.codingapi.flow.exception.FlowConfigException;
99
import com.codingapi.flow.form.FormMeta;
1010
import com.codingapi.flow.manager.ActionManager;
11+
import com.codingapi.flow.manager.FlowNodeState;
1112
import com.codingapi.flow.manager.NodeStrategyManager;
1213
import com.codingapi.flow.node.nodes.ApprovalNode;
1314
import com.codingapi.flow.node.nodes.HandleNode;
@@ -147,7 +148,7 @@ public Map<String, Object> toMap() {
147148
map.put("name", name);
148149
map.put("type", getType());
149150
map.put("order", String.valueOf(order));
150-
if(this.blocks!=null && !this.blocks.isEmpty()) {
151+
if (this.blocks != null && !this.blocks.isEmpty()) {
151152
map.put("blocks", blocks.stream().map(IFlowNode::toMap).toList());
152153
}
153154
map.put("actions", actions.stream().map(IFlowAction::toMap).toList());
@@ -161,7 +162,7 @@ public static <T extends BaseFlowNode> T fromMap(Map<String, Object> map, Class<
161162
T node = IMapConvertor.fromMap(map, clazz);
162163
node.setId((String) map.get("id"));
163164
node.setName((String) map.get("name"));
164-
if(map.get("order")!=null) {
165+
if (map.get("order") != null) {
165166
node.setOrder(Integer.parseInt((String) map.get("order")));
166167
}
167168
node.setBlocks(NodeMapBuilder.loadNodes(map));
@@ -194,6 +195,14 @@ private void verifyDefaultConfig() {
194195
if (strategies == null) {
195196
throw FlowConfigException.strategiesNotNull();
196197
}
198+
199+
FlowNodeState nodeState = new FlowNodeState(this);
200+
if (nodeState.isBlockNode() || nodeState.isBranchNode()) {
201+
List<IFlowNode> blocks = this.blocks();
202+
if (blocks == null || blocks.isEmpty()) {
203+
throw FlowConfigException.nodeConfigError(id, "blocks can not be null");
204+
}
205+
}
197206
}
198207

199208
/**

flow-engine-framework/src/main/java/com/codingapi/flow/node/factory/NodeFactory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ private void initNodes() {
2828
nodesClasses.put(DelayNode.NODE_TYPE, DelayNode.class);
2929
nodesClasses.put(EndNode.NODE_TYPE, EndNode.class);
3030
nodesClasses.put(HandleNode.NODE_TYPE, HandleNode.class);
31+
nodesClasses.put(InclusiveNode.NODE_TYPE, InclusiveNode.class);
3132
nodesClasses.put(InclusiveBranchNode.NODE_TYPE, InclusiveBranchNode.class);
3233
nodesClasses.put(NotifyNode.NODE_TYPE, NotifyNode.class);
3334
nodesClasses.put(RouterNode.NODE_TYPE, RouterNode.class);
35+
nodesClasses.put(ParallelNode.NODE_TYPE, ParallelNode.class);
3436
nodesClasses.put(ParallelBranchNode.NODE_TYPE, ParallelBranchNode.class);
3537
nodesClasses.put(StartNode.NODE_TYPE, StartNode.class);
3638
nodesClasses.put(SubProcessNode.NODE_TYPE, SubProcessNode.class);
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.codingapi.flow.node.nodes;
2+
3+
import com.codingapi.flow.builder.BaseNodeBuilder;
4+
import com.codingapi.flow.exception.FlowConfigException;
5+
import com.codingapi.flow.node.BaseFlowNode;
6+
import com.codingapi.flow.node.IFlowNode;
7+
import com.codingapi.flow.node.NodeType;
8+
import com.codingapi.flow.node.helper.ParallelNodeRelationHelper;
9+
import com.codingapi.flow.record.FlowRecord;
10+
import com.codingapi.flow.session.FlowSession;
11+
import com.codingapi.flow.utils.RandomUtils;
12+
import com.codingapi.flow.workflow.Workflow;
13+
14+
import java.util.List;
15+
import java.util.Map;
16+
17+
/**
18+
* 包容控制节点
19+
*/
20+
public class InclusiveNode extends BaseFlowNode {
21+
22+
public static final String NODE_TYPE = NodeType.INCLUSIVE.name();
23+
public static final String DEFAULT_NAME = "包容控制节点";
24+
25+
26+
@Override
27+
public String getType() {
28+
return NODE_TYPE;
29+
}
30+
31+
32+
public InclusiveNode(String id, String name, int order) {
33+
super(id, name, order);
34+
}
35+
36+
public InclusiveNode() {
37+
this(RandomUtils.generateStringId(), DEFAULT_NAME, 0);
38+
}
39+
40+
/**
41+
* 匹配条件
42+
*/
43+
@Override
44+
public boolean handle(FlowSession request) {
45+
return true;
46+
}
47+
48+
49+
public static InclusiveNode formMap(Map<String, Object> map) {
50+
return BaseFlowNode.fromMap(map, InclusiveNode.class);
51+
}
52+
53+
/**
54+
* 匹配条件分支
55+
*
56+
* @param nodeList 当前节点下的所有条件
57+
* @param flowSession 当前会话
58+
* @return 匹配的节点
59+
*/
60+
public List<IFlowNode> filterBranches(List<IFlowNode> nodeList, FlowSession flowSession) {
61+
Workflow workflow = flowSession.getWorkflow();
62+
ParallelNodeRelationHelper helper = new ParallelNodeRelationHelper(nodeList, workflow);
63+
// 分析并行分支的结束汇聚节点
64+
IFlowNode overNode = helper.fetchParallelEndNode();
65+
if (overNode == null) {
66+
throw FlowConfigException.parallelEndNodeNotNull();
67+
}
68+
69+
// 在流程记录中记录,合并的条件信息。
70+
FlowRecord flowRecord = flowSession.getCurrentRecord();
71+
flowRecord.parallelBranchNode(overNode.getId(), nodeList.size(), RandomUtils.generateStringId());
72+
73+
return nodeList;
74+
}
75+
76+
public static Builder builder() {
77+
return new Builder();
78+
}
79+
80+
public static class Builder extends BaseNodeBuilder<Builder, InclusiveNode> {
81+
82+
public Builder() {
83+
super(new InclusiveNode());
84+
}
85+
}
86+
}

flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
import java.util.Map;
1616

1717
/**
18-
* 并行节点
18+
* 并行分支节点
1919
*/
2020
public class ParallelBranchNode extends BaseFlowNode {
2121

2222
public static final String NODE_TYPE = NodeType.PARALLEL_BRANCH.name();
23-
public static final String DEFAULT_NAME = "并行节点";
23+
public static final String DEFAULT_NAME = "并行分支节点";
2424

2525
@Override
2626
public String getType() {

0 commit comments

Comments
 (0)