feat: 关系校验基本完成, runner入参确定

This commit is contained in:
2025-04-08 00:02:28 +08:00
parent 8174c33e31
commit 84ed63b894
22 changed files with 422 additions and 47 deletions

View File

@@ -30,7 +30,7 @@ public class ProcessDefinitionFacade {
} }
public App getByDeploymentId(Long deploymentId) { public App getByDeploymentId(Long deploymentId) {
return appEngineService.getByDeploymentId(deploymentId); return appEngineService.getByWorkflowId(deploymentId);
} }
public void update(ProcessBo processBo) { public void update(ProcessBo processBo) {

View File

@@ -1,9 +1,16 @@
package com.metis.flow.domain.context; package com.metis.flow.domain.context;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.metis.flow.runner.FlowRunningContext;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@Data @Data
@Builder
public class RunningContext { public class RunningContext {
/** /**
@@ -16,4 +23,29 @@ public class RunningContext {
*/ */
private JSONObject custom; private JSONObject custom;
/**
* 节点运行上下文, 需要数据进行传递
*/
private Map<Long, JSONObject> nodeRunningContext;
/**
* 下一个运行节点id集合, 可能是多个
*/
private Set<Long> nextRunNodeId;
/**
* 构建上下文
*
* @param context 上下文
* @return {@link RunningContext }
*/
public static RunningContext buildContext(SysContext sysContext, FlowRunningContext context) {
return RunningContext.builder()
.sys(sysContext)
.custom(context.getCustom())
.nodeRunningContext(new HashMap<>())
.build();
}
} }

View File

@@ -1,19 +1,51 @@
package com.metis.flow.domain.context; package com.metis.flow.domain.context;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
@Data @Data
@Builder
public class SysContext { public class SysContext {
private List<String> file; /**
* 文件列表
*/
private List<String> files;
/**
* 沟通的内容
*/
private String query;
/**
* 对话数
*/
private Integer dialogueCount;
/**
* 沟通的id
*/
private String conversationId;
/**
* 应用程序id
*/
private Long appId; private Long appId;
/**
* 用户id
*/
private Long userId; private Long userId;
/**
* 工作流id
*/
private Long workflowId; private Long workflowId;
/**
* 实例id
*/
private Long instanceId; private Long instanceId;
} }

View File

@@ -1,7 +1,6 @@
package com.metis.flow.domain.entity.base; package com.metis.flow.domain.entity.base;
import com.metis.flow.enums.EdgeType; import com.metis.flow.enums.EdgeType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
@@ -11,7 +10,7 @@ public class Edge {
/** /**
* 唯一标识符 * 唯一标识符
*/ */
@NotBlank(message = "唯一标识符不能为空") @NotNull(message = "唯一标识符不能为空")
private String id; private String id;
/** /**
@@ -28,25 +27,25 @@ public class Edge {
/** /**
* 源节点ID,对应节点id * 源节点ID,对应节点id
*/ */
@NotBlank(message = "源节点ID不能为空") @NotNull(message = "源节点ID不能为空")
private String source; private Long source;
/** /**
* 目标节点ID,对应节点id * 目标节点ID,对应节点id
*/ */
@NotBlank(message = "目标节点ID不能为空") @NotNull(message = "目标节点ID不能为空")
private String target; private Long target;
/** /**
* 源句柄id * 源句柄id
*/ */
@NotBlank(message = "源句柄ID不能为空") @NotNull(message = "源句柄ID不能为空")
private String sourceHandle; private Long sourceHandle;
/** /**
* 目标句柄id * 目标句柄id
*/ */
@NotBlank(message = "目标句柄ID不能为空") @NotNull(message = "目标句柄ID不能为空")
private String targetHandle; private Long targetHandle;
/** /**
* 边是否动画true/false * 边是否动画true/false

View File

@@ -1,8 +1,7 @@
package com.metis.flow.domain.entity.base; package com.metis.flow.domain.entity.base;
import com.metis.flow.enums.PositionType;
import com.metis.flow.enums.HandleType; import com.metis.flow.enums.HandleType;
import jakarta.validation.constraints.NotBlank; import com.metis.flow.enums.PositionType;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
@@ -14,8 +13,8 @@ public class Handle {
/** /**
* 句柄id * 句柄id
*/ */
@NotBlank(message = "句柄id不能为空") @NotNull(message = "句柄id不能为空")
private String id; private Long id;
/** /**
* 句柄类型 * 句柄类型

View File

@@ -5,7 +5,6 @@ import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.metis.flow.enums.NodeType; import com.metis.flow.enums.NodeType;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
@@ -18,8 +17,8 @@ public class Node {
/** /**
* id * id
*/ */
@NotBlank(message = "节点id不能为空") @NotNull(message = "节点id不能为空")
private String id; private Long id;
/** /**
* 类型 * 类型
@@ -43,7 +42,7 @@ public class Node {
@JsonIgnore @JsonIgnore
public Map<String, Handle> getHandleMap() { public Map<Long, Handle> getHandleMap() {
if (CollUtil.isEmpty(data.getHandles())) { if (CollUtil.isEmpty(data.getHandles())) {
return Map.of(); return Map.of();
} }

View File

@@ -1,6 +0,0 @@
package com.metis.flow.engine;
public interface AppEngineRunnerService {
}

View File

@@ -26,6 +26,14 @@ public interface AppEngineService {
List<App> list(AppQuery query); List<App> list(AppQuery query);
/**
* 通过应用id获取
*
* @param appId 应用程序id
* @return {@link App }
*/
App getByAppId(Long appId);
/** /**
* 按身份证领取 * 按身份证领取
* *
@@ -37,10 +45,10 @@ public interface AppEngineService {
/** /**
* 通过部署id获取 * 通过部署id获取
* *
* @param deploymentId 部署id * @param workflowId 部署id
* @return {@link App } * @return {@link App }
*/ */
App getByDeploymentId(Long deploymentId); App getByWorkflowId(Long workflowId);
/** /**
* 按id列表 * 按id列表

View File

@@ -0,0 +1,27 @@
package com.metis.flow.engine;
import com.metis.flow.runner.FlowRunningContext;
import com.metis.flow.runner.RunnerResult;
/**
* 应用引擎运行器服务
*
* @author clay
* @date 2025/04/07
*/
public interface AppFlowEngineRunnerService {
/**
* 运行
*
* @param context 上下文
* @return {@link RunnerResult }
*/
RunnerResult running(FlowRunningContext context);
}

View File

@@ -42,6 +42,12 @@ public class AppEngineServiceImpl implements AppEngineService {
return BaseAppConvert.INSTANCE.toApps(list); return BaseAppConvert.INSTANCE.toApps(list);
} }
@Override
public App getByAppId(Long appId) {
BaseApp baseApp = baseAppService.getByAppId(appId);
return BaseAppConvert.INSTANCE.toApp(baseApp);
}
@Override @Override
public App getByAppId(Long appId, Integer version) { public App getByAppId(Long appId, Integer version) {
BaseApp baseApp = baseAppService.getByAppIdAndVersion(appId, version); BaseApp baseApp = baseAppService.getByAppIdAndVersion(appId, version);
@@ -49,8 +55,8 @@ public class AppEngineServiceImpl implements AppEngineService {
} }
@Override @Override
public App getByDeploymentId(Long deploymentId) { public App getByWorkflowId(Long workflowId) {
BaseApp baseApp = baseAppService.getById(deploymentId); BaseApp baseApp = baseAppService.getById(workflowId);
return BaseAppConvert.INSTANCE.toApp(baseApp); return BaseAppConvert.INSTANCE.toApp(baseApp);
} }

View File

@@ -0,0 +1,57 @@
package com.metis.flow.engine.impl;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.metis.flow.domain.context.RunningContext;
import com.metis.flow.domain.context.SysContext;
import com.metis.flow.domain.entity.App;
import com.metis.flow.engine.AppEngineService;
import com.metis.flow.engine.AppFlowEngineRunnerService;
import com.metis.flow.runner.FlowRunningContext;
import com.metis.flow.runner.RunnerResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class AppFlowEngineRunnerServiceImpl implements AppFlowEngineRunnerService {
private final AppEngineService appEngineService;
@Override
public RunnerResult running(FlowRunningContext context) {
App app = getApp(context);
// todo 构建运行实例, 并将运行实例放入上下文
Long instanceId = IdUtil.getSnowflakeNextId();
// 构建系统上下文信息
SysContext sysContext = SysContext.builder()
.files(context.getFiles())
.appId(app.getId())
.workflowId(app.getWorkflowId())
.instanceId(instanceId)
.build();
// 构建运行中上下文
RunningContext runningContext = RunningContext.buildContext(sysContext, context);
return null;
}
/**
* 获取到应用程序信息
*
* @param context 上下文
* @return {@link App }
*/
private App getApp(FlowRunningContext context) {
if (ObjectUtil.isNull(context.getWorkflowId())) {
return appEngineService.getByWorkflowId(context.getWorkflowId());
}
return appEngineService.getByAppId(context.getAppId());
}
}

View File

@@ -0,0 +1,45 @@
package com.metis.flow.runner;
import com.alibaba.fastjson2.JSONObject;
import lombok.Builder;
import lombok.Data;
import java.util.List;
/**
* 运行上下文
*
* @author clay
* @date 2025/04/07
*/
@Data
@Builder
public class FlowRunningContext {
/**
* 文件列表
*/
private List<String> files;
/**
* 应用程序id
*/
private Long appId;
/**
* 用户id
*/
private Long userId;
/**
* 工作流id
*/
private Long workflowId;
/**
* 自定义
*/
private JSONObject custom;
}

View File

@@ -1,9 +1,12 @@
package com.metis.flow.runner; package com.metis.flow.runner;
import com.metis.flow.domain.context.RunningContext; import com.metis.flow.domain.context.RunningContext;
import com.metis.flow.domain.entity.base.Edge;
import com.metis.flow.domain.entity.base.Node; import com.metis.flow.domain.entity.base.Node;
import com.metis.flow.enums.NodeType; import com.metis.flow.enums.NodeType;
import java.util.List;
public interface NodeRunner { public interface NodeRunner {
@@ -12,9 +15,10 @@ public interface NodeRunner {
* *
* @param context 上下文 * @param context 上下文
* @param node 节点配置信息 * @param node 节点配置信息
* @param edges
* @return {@link RunningContext } * @return {@link RunningContext }
*/ */
RunningContext run(RunningContext context, Node node); RunningContext run(RunningContext context, Node node, List<Edge> edges);
/** /**

View File

@@ -8,6 +8,12 @@ import org.springframework.stereotype.Service;
import java.util.Map; import java.util.Map;
/**
* runner初始化
*
* @author clay
* @date 2025/04/07
*/
@Service @Service
public class RunnerInitialize implements ApplicationContextAware { public class RunnerInitialize implements ApplicationContextAware {

View File

@@ -0,0 +1,27 @@
package com.metis.flow.runner;
import com.metis.flow.domain.context.SysContext;
import lombok.Data;
/**
* 运行结果
*
* @author clay
* @date 2025/04/07
*/
@Data
public class RunnerResult {
/**
* 运行内容
*/
private String content;
/**
* 上下文
*/
private SysContext context;
}

View File

@@ -2,18 +2,21 @@ package com.metis.flow.runner.impl;
import com.metis.flow.domain.context.RunningContext; import com.metis.flow.domain.context.RunningContext;
import com.metis.flow.domain.entity.base.Edge;
import com.metis.flow.domain.entity.base.Node; import com.metis.flow.domain.entity.base.Node;
import com.metis.flow.enums.NodeType; import com.metis.flow.enums.NodeType;
import com.metis.flow.runner.NodeRunner; import com.metis.flow.runner.NodeRunner;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j @Slf4j
@Service @Service
public class EndNodeRunner implements NodeRunner { public class EndNodeRunner implements NodeRunner {
@Override @Override
public RunningContext run(RunningContext context, Node node) { public RunningContext run(RunningContext context, Node node, List<Edge> edges) {
return context; return context;
} }

View File

@@ -1,18 +1,21 @@
package com.metis.flow.runner.impl; package com.metis.flow.runner.impl;
import com.metis.flow.domain.context.RunningContext; import com.metis.flow.domain.context.RunningContext;
import com.metis.flow.domain.entity.base.Edge;
import com.metis.flow.domain.entity.base.Node; import com.metis.flow.domain.entity.base.Node;
import com.metis.flow.enums.NodeType; import com.metis.flow.enums.NodeType;
import com.metis.flow.runner.NodeRunner; import com.metis.flow.runner.NodeRunner;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j @Slf4j
@Service @Service
public class StartNodeRunner implements NodeRunner { public class StartNodeRunner implements NodeRunner {
@Override @Override
public RunningContext run(RunningContext context, Node node) { public RunningContext run(RunningContext context, Node node, List<Edge> edges) {
return context; return context;
} }

View File

@@ -1,8 +1,11 @@
package com.metis.flow.validator; package com.metis.flow.validator;
import com.metis.flow.domain.entity.base.Edge;
import com.metis.flow.domain.entity.base.Node; import com.metis.flow.domain.entity.base.Node;
import com.metis.flow.enums.NodeType; import com.metis.flow.enums.NodeType;
import java.util.List;
public interface NodeValidator { public interface NodeValidator {
@@ -12,7 +15,18 @@ public interface NodeValidator {
* @param node 节点 * @param node 节点
* @return {@link ValidatorResult } * @return {@link ValidatorResult }
*/ */
ValidatorResult validate(Node node); ValidatorResult validateValue(Node node);
/**
* 验证关系
*
* @param node 节点
* @param sources 来源
* @param targets 目标
* @return {@link ValidatorResult }
*/
ValidatorResult validateRelation(Node node, List<Edge> sources, List<Edge> targets);
/** /**

View File

@@ -53,7 +53,7 @@ public class ValidatorServiceImpl implements ValidatorService {
NodeValidator validator = NodeValidatorFactory.get(type); NodeValidator validator = NodeValidatorFactory.get(type);
// 节点校验器 // 节点校验器
Assert.isTrue(ObjectUtil.isNotNull(validator), "无:{}类型的节点校验器", type.getName()); Assert.isTrue(ObjectUtil.isNotNull(validator), "无:{}类型的节点校验器", type.getName());
ValidatorResult result = validator.validate(node); ValidatorResult result = validator.validateValue(node);
// 返回值检查 // 返回值检查
Assert.isTrue(ObjectUtil.isNotNull(result), "类型:{} 的校验器无返回值", validator.getType().getName()); Assert.isTrue(ObjectUtil.isNotNull(result), "类型:{} 的校验器无返回值", validator.getType().getName());
if (!result.getValid()) { if (!result.getValid()) {
@@ -94,6 +94,9 @@ public class ValidatorServiceImpl implements ValidatorService {
* @param edges 边缘 * @param edges 边缘
*/ */
private void validateRelation(List<Node> nodes, List<Edge> edges) { private void validateRelation(List<Node> nodes, List<Edge> edges) {
// 0. 检查是否只有一个起始节点
validateSingleStartNode(nodes);
// 1. 检查线是否连接有效节点 // 1. 检查线是否连接有效节点
validateEdgeConnections(nodes, edges); validateEdgeConnections(nodes, edges);
@@ -102,16 +105,39 @@ public class ValidatorServiceImpl implements ValidatorService {
// 3. 检查是否存在孤立节点 // 3. 检查是否存在孤立节点
validateIsolatedNodes(nodes, edges); validateIsolatedNodes(nodes, edges);
// 4. 检查两个节点间是否有多根连线
validateMultipleEdgesBetweenNodes(edges);
// 5. 检查节点自己的关系信息
validateNodeRelations(nodes, edges);
} }
/**
* 检查是否只有一个起始节点
*
* @param nodes 节点
*/
private void validateSingleStartNode(List<Node> nodes) {
Long startNodeCount = nodes.stream()
.filter(node -> NodeType.START.equals(node.getType()))
.count();
Assert.isTrue(startNodeCount.equals(1L), "图中必须且只能有一个起始节点,当前起始节点数量: {}", startNodeCount);
}
/** /**
* 检查线是否连接有效节点 * 检查线是否连接有效节点
*
* @param nodes 节点
* @param edges 边缘
*/ */
private void validateEdgeConnections(List<Node> nodes, List<Edge> edges) { private void validateEdgeConnections(List<Node> nodes, List<Edge> edges) {
Map<String, Node> nodeMap = nodes.stream().collect(Collectors.toMap(Node::getId, Function.identity())); Map<Long, Node> nodeMap = nodes.stream().collect(Collectors.toMap(Node::getId, Function.identity()));
for (Edge edge : edges) { for (Edge edge : edges) {
String source = edge.getSource(); Long source = edge.getSource();
String target = edge.getTarget(); Long target = edge.getTarget();
Assert.isTrue(nodeMap.containsKey(source), "边 {} 的源节点 {} 不存在", edge.getLabel(), source); Assert.isTrue(nodeMap.containsKey(source), "边 {} 的源节点 {} 不存在", edge.getLabel(), source);
Assert.isTrue(nodeMap.containsKey(target), "边 {} 的目标节点 {} 不存在", edge.getLabel(), target); Assert.isTrue(nodeMap.containsKey(target), "边 {} 的目标节点 {} 不存在", edge.getLabel(), target);
} }
@@ -119,9 +145,12 @@ public class ValidatorServiceImpl implements ValidatorService {
/** /**
* 检查是否存在环结构 * 检查是否存在环结构
*
* @param nodes 节点
* @param edges 边缘
*/ */
private void validateCycle(List<Node> nodes, List<Edge> edges) { private void validateCycle(List<Node> nodes, List<Edge> edges) {
Map<String, List<String>> adjacencyList = buildAdjacencyList(edges); Map<Long, List<Long>> adjacencyList = buildAdjacencyList(edges);
for (Node node : nodes) { for (Node node : nodes) {
if (hasCycle(node.getId(), adjacencyList, new HashSet<>())) { if (hasCycle(node.getId(), adjacencyList, new HashSet<>())) {
throw new IllegalArgumentException("图中存在环结构,起始节点: " + node.getData().getLabel()); throw new IllegalArgumentException("图中存在环结构,起始节点: " + node.getData().getLabel());
@@ -131,9 +160,12 @@ public class ValidatorServiceImpl implements ValidatorService {
/** /**
* 检查是否存在孤立节点 * 检查是否存在孤立节点
*
* @param nodes 节点
* @param edges 边缘
*/ */
private void validateIsolatedNodes(List<Node> nodes, List<Edge> edges) { private void validateIsolatedNodes(List<Node> nodes, List<Edge> edges) {
Set<String> connectedNodes = new HashSet<>(); Set<Long> connectedNodes = new HashSet<>();
for (Edge edge : edges) { for (Edge edge : edges) {
connectedNodes.add(edge.getSource()); connectedNodes.add(edge.getSource());
connectedNodes.add(edge.getTarget()); connectedNodes.add(edge.getTarget());
@@ -145,9 +177,12 @@ public class ValidatorServiceImpl implements ValidatorService {
/** /**
* 构建邻接表 * 构建邻接表
*
* @param edges 边缘
* @return {@link Map }<{@link Long }, {@link List }<{@link Long }>>
*/ */
private Map<String, List<String>> buildAdjacencyList(List<Edge> edges) { private Map<Long, List<Long>> buildAdjacencyList(List<Edge> edges) {
Map<String, List<String>> adjacencyList = new HashMap<>(); Map<Long, List<Long>> adjacencyList = new HashMap<>();
for (Edge edge : edges) { for (Edge edge : edges) {
adjacencyList.computeIfAbsent(edge.getSource(), k -> new ArrayList<>()).add(edge.getTarget()); adjacencyList.computeIfAbsent(edge.getSource(), k -> new ArrayList<>()).add(edge.getTarget());
} }
@@ -156,13 +191,18 @@ public class ValidatorServiceImpl implements ValidatorService {
/** /**
* 深度优先搜索DFS检查环 * 深度优先搜索DFS检查环
*
* @param nodeId 节点id
* @param adjacencyList 邻接表
* @param visited 是否已经访问过了
* @return boolean
*/ */
private boolean hasCycle(String nodeId, Map<String, List<String>> adjacencyList, Set<String> visited) { private boolean hasCycle(Long nodeId, Map<Long, List<Long>> adjacencyList, Set<Long> visited) {
if (visited.contains(nodeId)) { if (visited.contains(nodeId)) {
return true; // 发现环 return true; // 发现环
} }
visited.add(nodeId); visited.add(nodeId);
for (String neighbor : adjacencyList.getOrDefault(nodeId, new ArrayList<>())) { for (Long neighbor : adjacencyList.getOrDefault(nodeId, new ArrayList<>())) {
if (hasCycle(neighbor, adjacencyList, visited)) { if (hasCycle(neighbor, adjacencyList, visited)) {
return true; return true;
} }
@@ -171,4 +211,40 @@ public class ValidatorServiceImpl implements ValidatorService {
return false; return false;
} }
/**
* 检查两个节点间是否有多根连线
*
* @param edges 边缘
*/
private void validateMultipleEdgesBetweenNodes(List<Edge> edges) {
Map<String, Integer> edgeCountMap = new HashMap<>();
for (Edge edge : edges) {
String key = edge.getSource() + "-" + edge.getTarget(); // 使用 source 和 target 作为唯一标识
edgeCountMap.put(key, edgeCountMap.getOrDefault(key, 0) + 1);
if (edgeCountMap.get(key) > 1) {
throw new IllegalArgumentException("节点 " + edge.getSource() + " 和节点 " + edge.getTarget() + " 之间存在多根连线");
}
}
}
/**
* 检查节点的关系信息
*/
private void validateNodeRelations(List<Node> nodes, List<Edge> edges) {
// 构建 source 和 target 的映射
Map<Long, List<Edge>> sourceMap = edges.stream().collect(Collectors.groupingBy(Edge::getSource));
Map<Long, List<Edge>> targetMap = edges.stream().collect(Collectors.groupingBy(Edge::getTarget));
for (Node node : nodes) {
NodeValidator validator = NodeValidatorFactory.get(node.getType());
// 获取当前节点的 source 和 target
List<Edge> sources = targetMap.getOrDefault(node.getId(), new ArrayList<>());
List<Edge> targets = sourceMap.getOrDefault(node.getId(), new ArrayList<>());
// 检查节点关系
ValidatorResult result = validator.validateRelation(node, sources, targets);
Assert.isTrue(result.getValid(), result.getMessage());
}
}
} }

View File

@@ -1,5 +1,7 @@
package com.metis.flow.validator.impl.node; package com.metis.flow.validator.impl.node;
import cn.hutool.core.lang.Assert;
import com.metis.flow.domain.entity.base.Edge;
import com.metis.flow.domain.entity.base.Node; import com.metis.flow.domain.entity.base.Node;
import com.metis.flow.domain.entity.config.node.DocumentExtractorNodeConfig; import com.metis.flow.domain.entity.config.node.DocumentExtractorNodeConfig;
import com.metis.flow.enums.NodeType; import com.metis.flow.enums.NodeType;
@@ -10,6 +12,8 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -17,13 +21,21 @@ public class DocumentExtractorNodeValidator implements NodeValidator {
private final ValidatorCodeService validatorCodeService; private final ValidatorCodeService validatorCodeService;
@Override @Override
public ValidatorResult validate(Node node) { public ValidatorResult validateValue(Node node) {
DocumentExtractorNodeConfig config = node.getConfig(); DocumentExtractorNodeConfig config = node.getConfig();
validatorCodeService.validateThrow(config); validatorCodeService.validateThrow(config);
// 业务检查未通过 // 业务检查未通过
return ValidatorResult.invalid("业务报错"); return ValidatorResult.invalid("业务报错");
} }
@Override
public ValidatorResult validateRelation(Node node, List<Edge> sources, List<Edge> targets) {
// 1. 检查 targets 数量是否等于 1只允许一个出
Assert.isTrue(targets.size() == 1, "节点 {} 的出连接数必须为 1当前数量: {}", node.getId(), targets.size());
return ValidatorResult.valid();
}
@Override @Override
public NodeType getType() { public NodeType getType() {
return NodeType.DOCUMENT_EXTRACTOR; return NodeType.DOCUMENT_EXTRACTOR;

View File

@@ -1,5 +1,7 @@
package com.metis.flow.validator.impl.node; package com.metis.flow.validator.impl.node;
import cn.hutool.core.lang.Assert;
import com.metis.flow.domain.entity.base.Edge;
import com.metis.flow.domain.entity.base.Node; import com.metis.flow.domain.entity.base.Node;
import com.metis.flow.enums.NodeType; import com.metis.flow.enums.NodeType;
import com.metis.flow.validator.NodeValidator; import com.metis.flow.validator.NodeValidator;
@@ -8,6 +10,8 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -16,7 +20,19 @@ public class EndNodeValidator implements NodeValidator {
@Override @Override
public ValidatorResult validate(Node node) { public ValidatorResult validateValue(Node node) {
return ValidatorResult.valid();
}
@Override
public ValidatorResult validateRelation(Node node, List<Edge> sources, List<Edge> targets) {
// 1. 结束节点不允许有目标连接
Assert.isTrue(targets.isEmpty(), "结束节点 {} 不允许有目标连接", node.getId());
// 2. 检查 sources 数量是否小于 handles 数量
int handleCount = node.getData().getHandles().size();
Assert.isTrue(sources.size() <= handleCount, "结束节点 {} 的源连接数超过 handles 数量", node.getId());
return ValidatorResult.valid(); return ValidatorResult.valid();
} }

View File

@@ -1,5 +1,7 @@
package com.metis.flow.validator.impl.node; package com.metis.flow.validator.impl.node;
import cn.hutool.core.lang.Assert;
import com.metis.flow.domain.entity.base.Edge;
import com.metis.flow.domain.entity.base.Node; import com.metis.flow.domain.entity.base.Node;
import com.metis.flow.enums.NodeType; import com.metis.flow.enums.NodeType;
import com.metis.flow.validator.NodeValidator; import com.metis.flow.validator.NodeValidator;
@@ -7,12 +9,26 @@ import com.metis.flow.validator.ValidatorResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j @Slf4j
@Service @Service
public class StartNodeValidator implements NodeValidator { public class StartNodeValidator implements NodeValidator {
@Override @Override
public ValidatorResult validate(Node node) { public ValidatorResult validateValue(Node node) {
return ValidatorResult.valid();
}
@Override
public ValidatorResult validateRelation(Node node, List<Edge> sources, List<Edge> targets) {
// 1. 开始节点不允许有源连接
Assert.isTrue(sources.isEmpty(), "开始节点 {} 不允许有源连接", node.getId());
// 2. 检查 targets 数量是否小于 handles 数量
int handleCount = node.getData().getHandles().size();
Assert.isTrue(targets.size() <= handleCount, "开始节点 {} 的目标连接数超过 handles 数量", node.getId());
return ValidatorResult.valid(); return ValidatorResult.valid();
} }