diff --git a/cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/DetailService.java b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/DetailService.java index 27dc39a8..7f6b31ce 100644 --- a/cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/DetailService.java +++ b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/DetailService.java @@ -1,104 +1,61 @@ package com.cameleer3.server.core.detail; -import com.cameleer3.server.core.storage.ExecutionRepository; +import com.cameleer3.server.core.storage.ExecutionStore; +import com.cameleer3.server.core.storage.ExecutionStore.ProcessorRecord; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.*; -/** - * Provides execution detail with reconstructed processor tree. - *

- * This is a plain class (no Spring annotations) -- it lives in the core module - * and is wired as a bean by the app module configuration. - */ public class DetailService { - private final ExecutionRepository repository; + private final ExecutionStore executionStore; - public DetailService(ExecutionRepository repository) { - this.repository = repository; + public DetailService(ExecutionStore executionStore) { + this.executionStore = executionStore; } - /** - * Get the full detail of a route execution, including the nested processor tree. - * - * @param executionId the execution ID to look up - * @return the execution detail, or empty if not found - */ public Optional getDetail(String executionId) { - return repository.findRawById(executionId) - .map(this::toDetail); + return executionStore.findById(executionId) + .map(exec -> { + List processors = executionStore.findProcessors(executionId); + List roots = buildTree(processors); + return new ExecutionDetail( + exec.executionId(), exec.routeId(), exec.agentId(), + exec.status(), exec.startTime(), exec.endTime(), + exec.durationMs() != null ? exec.durationMs() : 0L, + exec.correlationId(), exec.exchangeId(), + exec.errorMessage(), exec.errorStacktrace(), + exec.diagramContentHash(), roots + ); + }); } - private ExecutionDetail toDetail(RawExecutionRow row) { - List roots = reconstructTree( - row.processorIds(), - row.processorTypes(), - row.processorStatuses(), - row.processorStarts(), - row.processorEnds(), - row.processorDurations(), - row.processorDiagramNodeIds(), - row.processorErrorMessages(), - row.processorErrorStacktraces(), - row.processorDepths(), - row.processorParentIndexes() - ); + List buildTree(List processors) { + if (processors.isEmpty()) return List.of(); - return new ExecutionDetail( - row.executionId(), - row.routeId(), - row.agentId(), - row.status(), - row.startTime(), - row.endTime(), - row.durationMs(), - row.correlationId(), - row.exchangeId(), - row.errorMessage(), - row.errorStackTrace(), - row.diagramContentHash(), - roots - ); - } - - /** - * Reconstruct the nested processor tree from flat parallel arrays. - *

- * Uses parentIndexes to wire children: parentIndex == -1 means the node is a root. - * Otherwise, parentIndex is the array index of the parent node. - */ - List reconstructTree( - String[] ids, String[] types, String[] statuses, - java.time.Instant[] starts, java.time.Instant[] ends, long[] durations, - String[] diagramNodeIds, String[] errorMessages, String[] errorStacktraces, - int[] depths, int[] parentIndexes) { - - if (ids == null || ids.length == 0) { - return List.of(); - } - - int len = ids.length; - ProcessorNode[] nodes = new ProcessorNode[len]; - - for (int i = 0; i < len; i++) { - nodes[i] = new ProcessorNode( - ids[i], types[i], statuses[i], - starts[i], ends[i], durations[i], - diagramNodeIds[i], errorMessages[i], errorStacktraces[i] - ); + Map nodeMap = new LinkedHashMap<>(); + for (ProcessorRecord p : processors) { + nodeMap.put(p.processorId(), new ProcessorNode( + p.processorId(), p.processorType(), p.status(), + p.startTime(), p.endTime(), + p.durationMs() != null ? p.durationMs() : 0L, + p.diagramNodeId(), p.errorMessage(), p.errorStacktrace() + )); } List roots = new ArrayList<>(); - for (int i = 0; i < len; i++) { - if (parentIndexes[i] == -1) { - roots.add(nodes[i]); + for (ProcessorRecord p : processors) { + ProcessorNode node = nodeMap.get(p.processorId()); + if (p.parentProcessorId() == null) { + roots.add(node); } else { - nodes[parentIndexes[i]].addChild(nodes[i]); + ProcessorNode parent = nodeMap.get(p.parentProcessorId()); + if (parent != null) { + parent.addChild(node); + } else { + roots.add(node); // orphan safety + } } } - return roots; } }