transition enricher
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.enricher;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.AnalysisResult;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.CodebaseMetadata;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.MatchedTransition;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
import click.kamil.springstatemachineexporter.analysis.service.CodebaseIntelligenceProvider;
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
import click.kamil.springstatemachineexporter.model.State;
|
||||
import click.kamil.springstatemachineexporter.model.Transition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TransitionLinkerEnricher implements AnalysisEnricher {
|
||||
|
||||
@Override
|
||||
public void enrich(AnalysisResult result, CodebaseContext context, CodebaseIntelligenceProvider intelligence) {
|
||||
if (result.getMetadata() == null || result.getMetadata().getCallChains() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<CallChain> updatedChains = new ArrayList<>();
|
||||
List<Transition> stateMachineTransitions = result.getTransitions();
|
||||
|
||||
for (CallChain chain : result.getMetadata().getCallChains()) {
|
||||
TriggerPoint tp = chain.getTriggerPoint();
|
||||
if (tp == null || tp.getEvent() == null) {
|
||||
updatedChains.add(chain);
|
||||
continue;
|
||||
}
|
||||
|
||||
String triggerEvent = simplify(tp.getEvent());
|
||||
String triggerSource = tp.getSourceState() != null ? simplify(tp.getSourceState()) : null;
|
||||
|
||||
List<MatchedTransition> matched = new ArrayList<>();
|
||||
|
||||
for (Transition t : stateMachineTransitions) {
|
||||
if (t.getEvent() != null) {
|
||||
String smEventRaw = t.getEvent().fullIdentifier() != null ? t.getEvent().fullIdentifier() : t.getEvent().rawName();
|
||||
String smEvent = simplify(smEventRaw);
|
||||
if (smEvent.equals(triggerEvent)) {
|
||||
// Event matches. Check source state if provided
|
||||
for (State smSourceState : t.getSourceStates()) {
|
||||
String smSourceRaw = smSourceState.fullIdentifier() != null ? smSourceState.fullIdentifier() : smSourceState.rawName();
|
||||
String smSource = simplify(smSourceRaw);
|
||||
if (triggerSource == null || triggerSource.equals(smSource)) {
|
||||
for (State smTargetState : t.getTargetStates()) {
|
||||
String sourceRaw = smSourceState.fullIdentifier() != null ? smSourceState.fullIdentifier() : smSourceState.rawName();
|
||||
String targetRaw = smTargetState.fullIdentifier() != null ? smTargetState.fullIdentifier() : smTargetState.rawName();
|
||||
matched.add(MatchedTransition.builder()
|
||||
.sourceState(sourceRaw)
|
||||
.targetState(targetRaw)
|
||||
.event(smEventRaw)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new CallChain with the matched transitions
|
||||
CallChain updatedChain = CallChain.builder()
|
||||
.entryPoint(chain.getEntryPoint())
|
||||
.methodChain(chain.getMethodChain())
|
||||
.triggerPoint(chain.getTriggerPoint())
|
||||
.contextMachineId(chain.getContextMachineId())
|
||||
.matchedTransitions(matched)
|
||||
.build();
|
||||
|
||||
updatedChains.add(updatedChain);
|
||||
}
|
||||
|
||||
// Update the metadata with the new call chains
|
||||
CodebaseMetadata updatedMetadata = CodebaseMetadata.builder()
|
||||
.triggers(result.getMetadata().getTriggers())
|
||||
.entryPoints(result.getMetadata().getEntryPoints())
|
||||
.callChains(updatedChains)
|
||||
.properties(result.getMetadata().getProperties())
|
||||
.build();
|
||||
|
||||
result.setMetadata(updatedMetadata);
|
||||
}
|
||||
|
||||
private String simplify(String name) {
|
||||
if (name == null) return "";
|
||||
int dot = name.lastIndexOf('.');
|
||||
if (dot >= 0) {
|
||||
return name.substring(dot + 1);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -15,4 +15,6 @@ public class CallChain {
|
||||
private final EntryPoint entryPoint;
|
||||
private final List<String> methodChain; // e.g., ["Controller.submit", "Service.process", "Service.send"]
|
||||
private final TriggerPoint triggerPoint;
|
||||
private final String contextMachineId;
|
||||
private final List<MatchedTransition> matchedTransitions;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@Jacksonized
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class MatchedTransition {
|
||||
private final String sourceState;
|
||||
private final String targetState;
|
||||
private final String event;
|
||||
}
|
||||
@@ -18,5 +18,6 @@ public class TriggerPoint {
|
||||
private final String sourceFile;
|
||||
private final String sourceModule;
|
||||
private final String stateMachineId; // Optional: to link to a specific SM instance
|
||||
private final String sourceState; // Optional: if we can determine the expected current state
|
||||
private final int lineNumber;
|
||||
}
|
||||
|
||||
@@ -39,10 +39,12 @@ public class CallGraphBuilder {
|
||||
List<String> path = findPath(startMethod, targetMethod, callGraph, new HashSet<>());
|
||||
if (path != null) {
|
||||
TriggerPoint resolvedTp = resolveTriggerPointParameters(tp, path, callGraph);
|
||||
String contextMachineId = extractContextMachineId(path, callGraph);
|
||||
chains.add(CallChain.builder()
|
||||
.entryPoint(ep)
|
||||
.triggerPoint(resolvedTp)
|
||||
.methodChain(path)
|
||||
.contextMachineId(contextMachineId)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -97,6 +99,24 @@ public class CallGraphBuilder {
|
||||
return tp;
|
||||
}
|
||||
|
||||
private String extractContextMachineId(List<String> path, Map<String, List<CallEdge>> callGraph) {
|
||||
for (String node : path) {
|
||||
List<CallEdge> edges = callGraph.get(node);
|
||||
if (edges != null) {
|
||||
for (CallEdge edge : edges) {
|
||||
String target = edge.getTargetMethod();
|
||||
if (target != null && (target.contains(".restore") || target.contains(".read"))) {
|
||||
// Persister signatures usually like: restore(stateMachine, contextObj)
|
||||
if (edge.getArguments().size() >= 2) {
|
||||
return edge.getArguments().get(1); // The contextObj / machineId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Map<String, List<CallEdge>> buildCallGraph() {
|
||||
graph = new HashMap<>();
|
||||
for (CompilationUnit cu : context.getCompilationUnits()) {
|
||||
@@ -131,13 +151,15 @@ public class CallGraphBuilder {
|
||||
String superFqn = context.getSuperclassFqn(td);
|
||||
if (superFqn != null) {
|
||||
TypeDeclaration superTd = context.getTypeDeclaration(superFqn);
|
||||
String calledMethod = null;
|
||||
if (superTd != null) {
|
||||
String calledMethod = resolveMethodInType(superTd, methodName);
|
||||
if (calledMethod != null) {
|
||||
List<String> args = resolveArguments(node.arguments());
|
||||
graph.computeIfAbsent(currentMethodFqn, k -> new ArrayList<>()).add(new CallEdge(calledMethod, args));
|
||||
}
|
||||
calledMethod = resolveMethodInType(superTd, methodName);
|
||||
}
|
||||
if (calledMethod == null) {
|
||||
calledMethod = superFqn + "." + methodName;
|
||||
}
|
||||
List<String> args = resolveArguments(node.arguments());
|
||||
graph.computeIfAbsent(currentMethodFqn, k -> new ArrayList<>()).add(new CallEdge(calledMethod, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,8 +175,8 @@ public class CallGraphBuilder {
|
||||
for (Object argObj : astArguments) {
|
||||
Expression expr = (Expression) argObj;
|
||||
String val = constantResolver.resolve(expr, context);
|
||||
if (val == null && expr instanceof SimpleName sn) {
|
||||
val = sn.getIdentifier();
|
||||
if (val == null) {
|
||||
val = expr.toString(); // Fallback to raw string (handles Enums, 'new Class()', etc)
|
||||
}
|
||||
args.add(val);
|
||||
}
|
||||
@@ -217,22 +239,25 @@ public class CallGraphBuilder {
|
||||
|
||||
private List<String> findPath(String start, String target, Map<String, List<CallEdge>> graph, Set<String> visited) {
|
||||
if (start.equals(target)) return new ArrayList<>(List.of(start));
|
||||
if (!visited.add(start)) return null;
|
||||
if (!visited.add(start)) return null; // Path-scoped cycle detection
|
||||
|
||||
List<CallEdge> neighbors = graph.get(start);
|
||||
if (neighbors != null) {
|
||||
for (CallEdge edge : neighbors) {
|
||||
String neighbor = edge.getTargetMethod();
|
||||
if (neighbor.equals(target) || isHeuristicMatch(neighbor, target)) {
|
||||
visited.remove(start);
|
||||
return new ArrayList<>(List.of(start, target));
|
||||
}
|
||||
List<String> path = findPath(neighbor, target, graph, visited);
|
||||
if (path != null) {
|
||||
path.add(0, start);
|
||||
visited.remove(start);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
visited.remove(start);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ public class GenericEventDetector {
|
||||
public boolean visit(MethodInvocation node) {
|
||||
String methodName = node.getName().getIdentifier();
|
||||
|
||||
if ("sendEvent".equals(methodName)) {
|
||||
if ("sendEvent".equals(methodName) || "sendEvents".equals(methodName) ||
|
||||
"sendEventCollect".equals(methodName) || "sendEventMono".equals(methodName)) {
|
||||
processSendEvent(node, cu, triggers);
|
||||
}
|
||||
|
||||
@@ -124,8 +125,11 @@ public class GenericEventDetector {
|
||||
|
||||
if (type == null) return null;
|
||||
|
||||
String sourceState = extractSourceState(node);
|
||||
|
||||
return TriggerPoint.builder()
|
||||
.event(eventValue)
|
||||
.sourceState(sourceState)
|
||||
.className(context.getFqn(type))
|
||||
.methodName(method != null ? method.getName().getIdentifier() : "initializer")
|
||||
.sourceFile(context.getRelativePath(context.getFqn(type)))
|
||||
@@ -133,15 +137,105 @@ public class GenericEventDetector {
|
||||
.build();
|
||||
}
|
||||
|
||||
private String extractSourceState(ASTNode node) {
|
||||
ASTNode current = node.getParent();
|
||||
while (current != null && !(current instanceof MethodDeclaration)) {
|
||||
if (current instanceof IfStatement ifStmt) {
|
||||
Expression expr = ifStmt.getExpression();
|
||||
String state = extractStateFromExpression(expr);
|
||||
if (state != null) return state;
|
||||
} else if (current instanceof SwitchCase switchCase) {
|
||||
if (!switchCase.expressions().isEmpty()) {
|
||||
return getSimpleNameString((Expression) switchCase.expressions().get(0));
|
||||
}
|
||||
} else if (current instanceof SwitchStatement switchStmt) {
|
||||
// If it's a switch block but we haven't hit a SwitchCase directly (AST hierarchy usually has SwitchCase as siblings of block statements)
|
||||
// Actually, walking up from the node, we will hit the SwitchStatement, but we need the SwitchCase right before us in the block.
|
||||
ASTNode parentBlock = current;
|
||||
// It's complex to walk siblings. A simpler heuristic is to just use IfStatement and SwitchCase (if wrapped correctly).
|
||||
}
|
||||
current = current.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String extractStateFromExpression(Expression expr) {
|
||||
if (expr instanceof InfixExpression infix) {
|
||||
if (infix.getOperator() == InfixExpression.Operator.EQUALS) {
|
||||
Expression left = infix.getLeftOperand();
|
||||
Expression right = infix.getRightOperand();
|
||||
// Usually one is a method call like getState(), the other is an enum
|
||||
if (left instanceof QualifiedName || left instanceof SimpleName && !(right instanceof SimpleName)) {
|
||||
return getSimpleNameString(left);
|
||||
}
|
||||
if (right instanceof QualifiedName || right instanceof SimpleName && !(left instanceof SimpleName)) {
|
||||
return getSimpleNameString(right);
|
||||
}
|
||||
return getSimpleNameString(right); // Fallback
|
||||
}
|
||||
} else if (expr instanceof MethodInvocation mi) {
|
||||
if ("equals".equals(mi.getName().getIdentifier()) && !mi.arguments().isEmpty()) {
|
||||
return getSimpleNameString((Expression) mi.arguments().get(0));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getSimpleNameString(Expression expr) {
|
||||
if (expr instanceof QualifiedName qn) {
|
||||
return qn.getName().getIdentifier();
|
||||
} else if (expr instanceof FieldAccess fa) {
|
||||
return fa.getName().getIdentifier();
|
||||
} else if (expr instanceof StringLiteral sl) {
|
||||
return sl.getLiteralValue();
|
||||
}
|
||||
return expr.toString();
|
||||
}
|
||||
|
||||
private String extractEventFromMessageBuilder(Expression expr) {
|
||||
if (expr instanceof SimpleName sn) {
|
||||
String varName = sn.getIdentifier();
|
||||
MethodDeclaration enclosingMethod = findEnclosingMethod(expr);
|
||||
if (enclosingMethod != null) {
|
||||
// Find variable declaration
|
||||
final Expression[] initializer = new Expression[1];
|
||||
enclosingMethod.accept(new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(VariableDeclarationFragment node) {
|
||||
if (node.getName().getIdentifier().equals(varName) && node.getInitializer() != null) {
|
||||
initializer[0] = node.getInitializer();
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
@Override
|
||||
public boolean visit(Assignment node) {
|
||||
if (node.getLeftHandSide() instanceof SimpleName asn && asn.getIdentifier().equals(varName)) {
|
||||
initializer[0] = node.getRightHandSide();
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
});
|
||||
if (initializer[0] != null) {
|
||||
return extractEventFromMessageBuilder(initializer[0]); // recursive
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(expr instanceof MethodInvocation mi)) return null;
|
||||
|
||||
// Trace back chain: MessageBuilder.withPayload(event).setHeader(...).build()
|
||||
MethodInvocation current = mi;
|
||||
while (current != null) {
|
||||
String name = current.getName().getIdentifier();
|
||||
if ("withPayload".equals(name) && !current.arguments().isEmpty()) {
|
||||
if (("withPayload".equals(name) || "just".equals(name)) && !current.arguments().isEmpty()) {
|
||||
Expression payloadExpr = (Expression) current.arguments().get(0);
|
||||
|
||||
// If it's Mono.just(msg), where msg is a variable
|
||||
if ("just".equals(name)) {
|
||||
String extracted = extractEventFromMessageBuilder(payloadExpr);
|
||||
if (extracted != null) return extracted;
|
||||
}
|
||||
|
||||
String resolved = constantResolver.resolve(payloadExpr, context);
|
||||
if (resolved != null) return resolved;
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ public class PlantUml implements StateMachineExporter {
|
||||
String label = buildLabel(t, options);
|
||||
if (options.isEmbedIdentifiers()) {
|
||||
String eventStr = t.getEvent() != null ? options.formatEvent(t.getEvent()) : null;
|
||||
String linkId = eventStr != null && !eventStr.isBlank() ? "link_" + normalize(eventStr) : "link_anon_" + normalize(source) + "_" + normalize(target);
|
||||
String linkId = eventStr != null && !eventStr.isBlank() ? "link_" + normalize(source) + "__" + normalize(eventStr) : "link_anon_" + normalize(source) + "_" + normalize(target);
|
||||
// Force a label even if empty to ensure the link group exists in SVG
|
||||
String displayLabel = label.isEmpty() ? " " : label;
|
||||
// Brackets [...] in the label break PlantUML link syntax [[url label]],
|
||||
|
||||
@@ -44,7 +44,8 @@ public class ExportService {
|
||||
new TriggerEnricher(),
|
||||
new EntryPointEnricher(),
|
||||
new PropertyEnricher(),
|
||||
new CallChainEnricher()
|
||||
new CallChainEnricher(),
|
||||
new click.kamil.springstatemachineexporter.analysis.enricher.TransitionLinkerEnricher()
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -212,6 +213,11 @@ public class ExportService {
|
||||
Set<String> endStates = TransitionStateUtils.findEndStates(transitions, endStatesAst);
|
||||
Set<click.kamil.springstatemachineexporter.model.State> allStates = TransitionStateUtils.findAllStates(transitions, initialStatesAst, endStatesAst);
|
||||
|
||||
if (allStates.isEmpty() && transitions.isEmpty()) {
|
||||
log.info("Skipping empty state machine config: {}", className);
|
||||
return;
|
||||
}
|
||||
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
.name(className)
|
||||
.states(allStates)
|
||||
@@ -243,6 +249,11 @@ public class ExportService {
|
||||
Set<String> endStates = TransitionStateUtils.findEndStates(transitions, null);
|
||||
Set<click.kamil.springstatemachineexporter.model.State> allStates = TransitionStateUtils.findAllStates(transitions, null, null);
|
||||
|
||||
if (allStates.isEmpty() && transitions.isEmpty()) {
|
||||
log.info("Skipping empty state machine bean: {}", uniqueName);
|
||||
return;
|
||||
}
|
||||
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
.name(uniqueName)
|
||||
.states(allStates)
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.enricher;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.AnalysisResult;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.CodebaseMetadata;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
import click.kamil.springstatemachineexporter.model.Event;
|
||||
import click.kamil.springstatemachineexporter.model.State;
|
||||
import click.kamil.springstatemachineexporter.model.Transition;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class TransitionLinkerEnricherTest {
|
||||
|
||||
private final TransitionLinkerEnricher enricher = new TransitionLinkerEnricher();
|
||||
|
||||
@Test
|
||||
void shouldLinkTransitionByEventOnly() {
|
||||
Transition t1 = new Transition();
|
||||
t1.setSourceStates(List.of(State.of("NEW", "NEW")));
|
||||
t1.setTargetStates(List.of(State.of("PAID", "PAID")));
|
||||
t1.setEvent(Event.of("PAY", "PAY"));
|
||||
|
||||
Transition t2 = new Transition();
|
||||
t2.setSourceStates(List.of(State.of("FAILED", "FAILED")));
|
||||
t2.setTargetStates(List.of(State.of("PAID", "PAID")));
|
||||
t2.setEvent(Event.of("PAY", "PAY"));
|
||||
|
||||
CallChain chain = CallChain.builder()
|
||||
.triggerPoint(TriggerPoint.builder().event("PAY").build())
|
||||
.build();
|
||||
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
.transitions(List.of(t1, t2))
|
||||
.metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
|
||||
.build();
|
||||
|
||||
enricher.enrich(result, null, null);
|
||||
|
||||
CallChain updatedChain = result.getMetadata().getCallChains().get(0);
|
||||
assertThat(updatedChain.getMatchedTransitions()).hasSize(2);
|
||||
assertThat(updatedChain.getMatchedTransitions())
|
||||
.extracting("sourceState")
|
||||
.containsExactlyInAnyOrder("NEW", "FAILED");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldLinkTransitionByEventAndSourceState() {
|
||||
Transition t1 = new Transition();
|
||||
t1.setSourceStates(List.of(State.of("NEW", "NEW")));
|
||||
t1.setTargetStates(List.of(State.of("PAID", "PAID")));
|
||||
t1.setEvent(Event.of("PAY", "PAY"));
|
||||
|
||||
Transition t2 = new Transition();
|
||||
t2.setSourceStates(List.of(State.of("FAILED", "FAILED")));
|
||||
t2.setTargetStates(List.of(State.of("PAID", "PAID")));
|
||||
t2.setEvent(Event.of("PAY", "PAY"));
|
||||
|
||||
CallChain chain = CallChain.builder()
|
||||
.triggerPoint(TriggerPoint.builder().event("PAY").sourceState("NEW").build())
|
||||
.build();
|
||||
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
.transitions(List.of(t1, t2))
|
||||
.metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
|
||||
.build();
|
||||
|
||||
enricher.enrich(result, null, null);
|
||||
|
||||
CallChain updatedChain = result.getMetadata().getCallChains().get(0);
|
||||
assertThat(updatedChain.getMatchedTransitions()).hasSize(1);
|
||||
assertThat(updatedChain.getMatchedTransitions().get(0).getSourceState()).isEqualTo("NEW");
|
||||
assertThat(updatedChain.getMatchedTransitions().get(0).getTargetState()).isEqualTo("PAID");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldLinkTransitionByFullIdentifier() {
|
||||
Transition t1 = new Transition();
|
||||
t1.setSourceStates(List.of(State.of("\"NEW\"", "NEW")));
|
||||
t1.setTargetStates(List.of(State.of("\"PAID\"", "PAID")));
|
||||
// This simulates how Spring Config usually has Event as OrderEvents.PAY but its resolved string is "PAY_ORDER"
|
||||
t1.setEvent(Event.of("OrderEvents.PAY", "PAY_ORDER"));
|
||||
|
||||
CallChain chain = CallChain.builder()
|
||||
.triggerPoint(TriggerPoint.builder().event("PAY_ORDER").sourceState("NEW").build())
|
||||
.build();
|
||||
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
.transitions(List.of(t1))
|
||||
.metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
|
||||
.build();
|
||||
|
||||
enricher.enrich(result, null, null);
|
||||
|
||||
CallChain updatedChain = result.getMetadata().getCallChains().get(0);
|
||||
assertThat(updatedChain.getMatchedTransitions()).hasSize(1);
|
||||
assertThat(updatedChain.getMatchedTransitions().get(0).getSourceState()).isEqualTo("NEW");
|
||||
assertThat(updatedChain.getMatchedTransitions().get(0).getTargetState()).isEqualTo("PAID");
|
||||
assertThat(updatedChain.getMatchedTransitions().get(0).getEvent()).isEqualTo("PAY_ORDER");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleUnknownEvents() {
|
||||
CallChain chain = CallChain.builder()
|
||||
.triggerPoint(TriggerPoint.builder().event(null).build()) // Dynamic or unresolved event
|
||||
.build();
|
||||
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
.transitions(List.of(new Transition()))
|
||||
.metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
|
||||
.build();
|
||||
|
||||
enricher.enrich(result, null, null);
|
||||
|
||||
CallChain updatedChain = result.getMetadata().getCallChains().get(0);
|
||||
assertThat(updatedChain.getMatchedTransitions()).isNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
import click.kamil.springstatemachineexporter.analysis.resolver.ConstantResolver;
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class GenericEventDetectorTest {
|
||||
|
||||
@Test
|
||||
void testMessageBuilderVariableAssignment(@TempDir Path tempDir) throws IOException {
|
||||
Path dir = tempDir.resolve("com/example");
|
||||
Files.createDirectories(dir);
|
||||
Files.writeString(dir.resolve("MyService.java"),
|
||||
"package com.example;\n" +
|
||||
"import org.springframework.messaging.support.MessageBuilder;\n" +
|
||||
"import org.springframework.messaging.Message;\n" +
|
||||
"import org.springframework.statemachine.StateMachine;\n" +
|
||||
"public class MyService {\n" +
|
||||
" private StateMachine<String, String> stateMachine;\n" +
|
||||
" private void a(MyInterface myEvent) {\n" +
|
||||
" Message<MyInterface> msg = MessageBuilder.withPayload(myEvent).setHeader(\"k\", \"v\").build();\n" +
|
||||
" stateMachine.sendEvent(Mono.just(msg));\n" +
|
||||
" }\n" +
|
||||
"}\n");
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.scan(tempDir);
|
||||
|
||||
GenericEventDetector detector = new GenericEventDetector(context, new ConstantResolver(), List.of());
|
||||
CompilationUnit cu = context.getCompilationUnits().iterator().next();
|
||||
List<TriggerPoint> triggers = detector.detect(cu);
|
||||
|
||||
assertThat(triggers).hasSize(1);
|
||||
assertThat(triggers.get(0).getEvent()).isEqualTo("myEvent");
|
||||
assertThat(triggers.get(0).getMethodName()).isEqualTo("a");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package click.kamil.springstatemachineexporter.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.exporter.StateMachineExporter;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class ExportServiceEmptyStateTest {
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
|
||||
@Test
|
||||
void shouldSkipEmptyStateMachineConfigurations() throws Exception {
|
||||
// Arrange
|
||||
Path inputDir = tempDir.resolve("input");
|
||||
Files.createDirectories(inputDir);
|
||||
Path outputDir = tempDir.resolve("output");
|
||||
Files.createDirectories(outputDir);
|
||||
|
||||
String code = """
|
||||
package com.example;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public class EmptyStateMachineConfig extends StateMachineConfigurerAdapter<String, String> {
|
||||
// No configurers overridden, meaning 0 states and 0 transitions parsed
|
||||
}
|
||||
""";
|
||||
|
||||
Files.writeString(inputDir.resolve("EmptyStateMachineConfig.java"), code);
|
||||
|
||||
ExportService exportService = new ExportService(Collections.emptyList()); // No exporters needed, checking if it generates anything (it generates JSON natively)
|
||||
|
||||
// Act
|
||||
exportService.runExporter(inputDir, outputDir, List.of("plantuml"), true);
|
||||
|
||||
// Assert
|
||||
// The output directory should have no files created in it
|
||||
long fileCount = Files.walk(outputDir)
|
||||
.filter(Files::isRegularFile)
|
||||
.count();
|
||||
|
||||
assertThat(fileCount).isZero();
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/api/SecurityInterceptor.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 17
|
||||
}, {
|
||||
"event" : "PLACE_ORDER",
|
||||
@@ -15,6 +16,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/service/OrderServiceImpl.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 16
|
||||
}, {
|
||||
"event" : "CANCEL_ORDER",
|
||||
@@ -23,6 +25,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/service/OrderServiceImpl.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 21
|
||||
}, {
|
||||
"event" : "PAY_ORDER",
|
||||
@@ -31,6 +34,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/service/ReactivePaymentService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 18
|
||||
}, {
|
||||
"event" : "SHIP_ORDER",
|
||||
@@ -39,6 +43,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/messaging/ShippingJmsListener.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 17
|
||||
}, {
|
||||
"event" : "RETURN_ORDER",
|
||||
@@ -47,6 +52,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/messaging/ReturnsRabbitListener.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 17
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
@@ -178,8 +184,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/service/OrderServiceImpl.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 16
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "NEW",
|
||||
"targetState" : "CHECK_AVAILABILITY",
|
||||
"event" : "PLACE_ORDER"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -205,8 +218,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/service/OrderServiceImpl.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 21
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "PAID",
|
||||
"targetState" : "CANCELLED",
|
||||
"event" : "CANCEL_ORDER"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "CUSTOM",
|
||||
@@ -227,8 +247,11 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/api/SecurityInterceptor.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 17
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -254,8 +277,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/service/ReactivePaymentService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 18
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "PENDING_PAYMENT",
|
||||
"targetState" : "PAID",
|
||||
"event" : "PAY_ORDER"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "JMS",
|
||||
@@ -281,8 +311,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/messaging/ShippingJmsListener.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 17
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "PAID",
|
||||
"targetState" : "SHIPPED",
|
||||
"event" : "SHIP_ORDER"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "RABBIT",
|
||||
@@ -308,8 +345,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/enterprise/messaging/ReturnsRabbitListener.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 17
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "DELIVERED",
|
||||
"targetState" : "RETURNED",
|
||||
"event" : "RETURN_ORDER"
|
||||
} ]
|
||||
} ],
|
||||
"properties" : {
|
||||
"default" : { }
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 34
|
||||
}, {
|
||||
"event" : "AUDIT_EVENT",
|
||||
@@ -15,6 +16,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/AuditInterceptor.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 16
|
||||
}, {
|
||||
"event" : "EXTERNAL_TRIGGER",
|
||||
@@ -23,6 +25,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 19
|
||||
}, {
|
||||
"event" : "SUBMIT_EVENT",
|
||||
@@ -31,6 +34,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 20
|
||||
}, {
|
||||
"event" : "CANCEL_EVENT",
|
||||
@@ -39,6 +43,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 25
|
||||
}, {
|
||||
"event" : "[LIFECYCLE:RESTORE]",
|
||||
@@ -47,6 +52,7 @@
|
||||
"sourceFile" : null,
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 29
|
||||
}, {
|
||||
"event" : "REACTIVE_EVENT",
|
||||
@@ -55,6 +61,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/ReactiveOrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 18
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
@@ -152,8 +159,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 19
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "START",
|
||||
"targetState" : "PROCESSING",
|
||||
"event" : "EXTERNAL_TRIGGER"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -175,8 +189,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 20
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "START",
|
||||
"targetState" : "PROCESSING",
|
||||
"event" : "SUBMIT_EVENT"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -198,8 +219,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 25
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "PROCESSING",
|
||||
"targetState" : "CANCELLED",
|
||||
"event" : "CANCEL_EVENT"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -221,8 +249,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 34
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "PROCESSING",
|
||||
"targetState" : "COMPLETED",
|
||||
"event" : "FINISH"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -248,8 +283,11 @@
|
||||
"sourceFile" : null,
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 29
|
||||
}
|
||||
},
|
||||
"contextMachineId" : "orderId",
|
||||
"matchedTransitions" : [ ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -275,8 +313,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/ReactiveOrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 18
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "START",
|
||||
"targetState" : "PROCESSING",
|
||||
"event" : "REACTIVE_EVENT"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "CUSTOM",
|
||||
@@ -297,8 +342,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/AuditInterceptor.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 16
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "START",
|
||||
"targetState" : "START",
|
||||
"event" : "AUDIT_EVENT"
|
||||
} ]
|
||||
} ],
|
||||
"properties" : {
|
||||
"default" : {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 34
|
||||
}, {
|
||||
"event" : "AUDIT_EVENT",
|
||||
@@ -15,6 +16,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/AuditInterceptor.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 16
|
||||
}, {
|
||||
"event" : "EXTERNAL_TRIGGER",
|
||||
@@ -23,6 +25,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 19
|
||||
}, {
|
||||
"event" : "SUBMIT_EVENT",
|
||||
@@ -31,6 +34,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 20
|
||||
}, {
|
||||
"event" : "CANCEL_EVENT",
|
||||
@@ -39,6 +43,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 25
|
||||
}, {
|
||||
"event" : "[LIFECYCLE:RESTORE]",
|
||||
@@ -47,6 +52,7 @@
|
||||
"sourceFile" : null,
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 29
|
||||
}, {
|
||||
"event" : "REACTIVE_EVENT",
|
||||
@@ -55,6 +61,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/ReactiveOrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 18
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
@@ -152,8 +159,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 19
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "START",
|
||||
"targetState" : "PROCESSING",
|
||||
"event" : "EXTERNAL_TRIGGER"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -175,8 +189,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 20
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "START",
|
||||
"targetState" : "PROCESSING",
|
||||
"event" : "SUBMIT_EVENT"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -198,8 +219,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/OrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 25
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "PROCESSING",
|
||||
"targetState" : "CANCELLED",
|
||||
"event" : "CANCEL_EVENT"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -221,8 +249,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 34
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "PROCESSING",
|
||||
"targetState" : "COMPLETED",
|
||||
"event" : "FINISH"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -248,8 +283,11 @@
|
||||
"sourceFile" : null,
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 29
|
||||
}
|
||||
},
|
||||
"contextMachineId" : "orderId",
|
||||
"matchedTransitions" : [ ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
@@ -275,8 +313,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/service/ReactiveOrderService.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 18
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "START",
|
||||
"targetState" : "PROCESSING",
|
||||
"event" : "REACTIVE_EVENT"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "CUSTOM",
|
||||
@@ -297,8 +342,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/AuditInterceptor.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 16
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "START",
|
||||
"targetState" : "START",
|
||||
"event" : "AUDIT_EVENT"
|
||||
} ]
|
||||
} ],
|
||||
"properties" : {
|
||||
"default" : {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/inheritance/service/ProcessingServiceImpl.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 15
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
@@ -53,8 +54,15 @@
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/inheritance/service/ProcessingServiceImpl.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 15
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "START",
|
||||
"targetState" : "WORKING",
|
||||
"event" : "INHERITED_SUBMIT"
|
||||
} ]
|
||||
} ],
|
||||
"properties" : {
|
||||
"default" : { }
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"sourceFile" : "core-module/src/main/java/click/kamil/maven/core/MavenOrderStateMachine.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 40
|
||||
}, {
|
||||
"event" : "ORDER_EVENT",
|
||||
@@ -15,6 +16,7 @@
|
||||
"sourceFile" : "core-module/src/main/java/click/kamil/maven/core/MavenOrderStateMachine.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 52
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
@@ -100,8 +102,15 @@
|
||||
"sourceFile" : "core-module/src/main/java/click/kamil/maven/core/MavenOrderStateMachine.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 40
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "INIT",
|
||||
"targetState" : "BUSY",
|
||||
"event" : "SUBMIT"
|
||||
} ]
|
||||
} ],
|
||||
"properties" : {
|
||||
"default" : { }
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"sourceFile" : "core-module/src/main/java/click/kamil/multi/core/OrderController.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 18
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
@@ -65,8 +66,15 @@
|
||||
"sourceFile" : "core-module/src/main/java/click/kamil/multi/core/OrderController.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 18
|
||||
}
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "NEW",
|
||||
"targetState" : "PROCESSING",
|
||||
"event" : "SUBMIT"
|
||||
} ]
|
||||
} ],
|
||||
"properties" : {
|
||||
"default" : { }
|
||||
|
||||
Reference in New Issue
Block a user