Link expanded generic REST paths via parameter alias tracking

Follow renamed path variables through call-graph aliases, expand machineType×event bindings from branch-scoped valueOf, treat fully resolved URLs as internal, and synthesize concrete polymorphic events from path constraints for transition linking.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-14 07:15:16 +02:00
parent 5d432e8893
commit e3f3350398
14 changed files with 1660 additions and 154 deletions

View File

@@ -57,6 +57,8 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
continue; continue;
} }
tp = MachineEnumCanonicalizer.expandBoundValueOfFromConstraints(
tp, machineTypes, context, chain.getEntryPoint());
tp = MachineEnumCanonicalizer.ensureCallChainPolymorphicEvents( tp = MachineEnumCanonicalizer.ensureCallChainPolymorphicEvents(
tp, machineTypes, context, stateMachineTransitions, true); tp, machineTypes, context, stateMachineTransitions, true);
tp = MachineEnumCanonicalizer.canonicalizeTriggerLabelsForLinking(tp, machineTypes, context); tp = MachineEnumCanonicalizer.canonicalizeTriggerLabelsForLinking(tp, machineTypes, context);
@@ -207,8 +209,20 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
if (constraint == null || machineName == null) { if (constraint == null || machineName == null) {
return true; return true;
} }
String machineConstraint = stripEventBindingClauses(constraint);
return BooleanConstraintEvaluator.isCompatibleWithMachineDomain( return BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
constraint, MachineDomainKeys.extractMachineDomainKey(machineName)); machineConstraint, MachineDomainKeys.extractMachineDomainKey(machineName));
}
private static String stripEventBindingClauses(String constraint) {
if (constraint == null || constraint.isBlank()) {
return constraint;
}
String stripped = constraint.replaceAll("\"[^\"]+\"\\.equalsIgnoreCase\\(event\\)", "true");
stripped = stripped.replaceAll("&&\\s*&&+", "&&");
stripped = stripped.replaceAll("^\\s*&&\\s*", "");
stripped = stripped.replaceAll("\\s*&&\\s*$", "");
return stripped.trim();
} }
private final java.util.Map<String, String> simplifySourceCache = new java.util.HashMap<>(); private final java.util.Map<String, String> simplifySourceCache = new java.util.HashMap<>();

View File

@@ -1,5 +1,6 @@
package click.kamil.springstatemachineexporter.analysis.resolver; package click.kamil.springstatemachineexporter.analysis.resolver;
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint; import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import click.kamil.springstatemachineexporter.model.Event; import click.kamil.springstatemachineexporter.model.Event;
@@ -999,4 +1000,86 @@ public final class MachineEnumCanonicalizer {
} }
return simpleName(enumTypeFqn) + "." + canonicalFqn.substring(lastDot + 1); return simpleName(enumTypeFqn) + "." + canonicalFqn.substring(lastDot + 1);
} }
/**
* When path bindings prove a single {@code event} literal (e.g. {@code "PAY".equalsIgnoreCase(event)})
* and the trigger is {@code Enum.valueOf(...)}, synthesize one concrete polymorphic event for linking.
*/
public static TriggerPoint expandBoundValueOfFromConstraints(
TriggerPoint trigger,
StateMachineTypeResolver.MachineTypes machineTypes,
CodebaseContext context) {
return expandBoundValueOfFromConstraints(trigger, machineTypes, context, null);
}
public static TriggerPoint expandBoundValueOfFromConstraints(
TriggerPoint trigger,
StateMachineTypeResolver.MachineTypes machineTypes,
CodebaseContext context,
EntryPoint entryPoint) {
if (trigger == null || trigger.getEvent() == null || machineTypes == null) {
return trigger;
}
if (!isDynamicTriggerExpression(trigger.getEvent()) || !trigger.getEvent().contains(".valueOf(")) {
return trigger;
}
String constraint = trigger.getConstraint();
if (constraint == null || constraint.isBlank()) {
return trigger;
}
List<String> boundEventLiterals = extractBoundEventLiteralsFromConstraint(constraint);
if (boundEventLiterals.size() != 1) {
return trigger;
}
String eventTypeFqn = machineTypes.eventTypeFqn();
if (eventTypeFqn == null || eventTypeFqn.isBlank()) {
return trigger;
}
String literal = boundEventLiterals.get(0).toUpperCase();
if (entryPoint != null && entryPoint.getName() != null
&& !entryPoint.getName().toUpperCase().contains("/" + literal + "/")
&& !entryPoint.getName().toUpperCase().endsWith("/" + literal)) {
return trigger;
}
String machineTypeLiteral = extractBoundParamLiteralFromConstraint(constraint, "machineType");
if (machineTypeLiteral != null && entryPoint != null && entryPoint.getName() != null
&& !entryPoint.getName().toUpperCase().contains("/" + machineTypeLiteral.toUpperCase() + "/")) {
return trigger;
}
String constantFqn = eventTypeFqn + "." + literal;
if (context != null) {
List<String> machineEnumValues = context.getEnumValues(eventTypeFqn);
if (machineEnumValues == null || machineEnumValues.stream().noneMatch(constantFqn::equals)) {
return trigger;
}
}
return trigger.toBuilder()
.polymorphicEvents(List.of(constantFqn))
.ambiguous(false)
.external(false)
.build();
}
private static String extractBoundParamLiteralFromConstraint(String constraint, String paramName) {
java.util.regex.Matcher matcher = java.util.regex.Pattern
.compile("\"([^\"]+)\"\\.equalsIgnoreCase\\(" + paramName + "\\)")
.matcher(constraint);
if (matcher.find()) {
return matcher.group(1);
}
return null;
}
private static List<String> extractBoundEventLiteralsFromConstraint(String constraint) {
List<String> literals = new ArrayList<>();
java.util.regex.Matcher matcher = java.util.regex.Pattern
.compile("\"([^\"]+)\"\\.equalsIgnoreCase\\((\\w+)\\)")
.matcher(constraint);
while (matcher.find()) {
if ("event".equals(matcher.group(2))) {
literals.add(matcher.group(1));
}
}
return literals;
}
} }

View File

@@ -2,6 +2,8 @@ package click.kamil.springstatemachineexporter.analysis.service;
import click.kamil.springstatemachineexporter.analysis.model.CallEdge; import click.kamil.springstatemachineexporter.analysis.model.CallEdge;
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint; import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
import click.kamil.springstatemachineexporter.analysis.resolver.BooleanConstraintEvaluator;
import click.kamil.springstatemachineexporter.ast.common.AstUtils;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext; import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.eclipse.jdt.core.dom.*; import org.eclipse.jdt.core.dom.*;
@@ -59,22 +61,26 @@ public final class EntryPointBindingExpander {
if (isPlaceholderResolvedInPath(entryPoint, parameter.getName())) { if (isPlaceholderResolvedInPath(entryPoint, parameter.getName())) {
continue; continue;
} }
List<String> cases = resolveBindingCasesForParameter(
entryPoint.getClassName() + "." + entryPoint.getMethodName(),
parameter.getName(),
context,
callGraph);
if (cases.isEmpty()) {
continue;
}
List<Map<String, String>> expanded = new ArrayList<>(); List<Map<String, String>> expanded = new ArrayList<>();
for (Map<String, String> base : variants) { for (Map<String, String> base : variants) {
List<String> cases = resolveBindingCasesForParameter(
entryPoint.getClassName() + "." + entryPoint.getMethodName(),
parameter.getName(),
context,
callGraph,
base);
if (cases.isEmpty()) {
continue;
}
for (String caseValue : cases) { for (String caseValue : cases) {
Map<String, String> merged = new LinkedHashMap<>(base); Map<String, String> merged = new LinkedHashMap<>(base);
merged.put(parameter.getName(), caseValue); merged.put(parameter.getName(), caseValue);
expanded.add(merged); expanded.add(merged);
} }
} }
if (expanded.isEmpty()) {
continue;
}
variants = expanded; variants = expanded;
} }
return variants.stream().filter(map -> !map.isEmpty()).toList(); return variants.stream().filter(map -> !map.isEmpty()).toList();
@@ -270,81 +276,149 @@ public final class EntryPointBindingExpander {
String startMethod, String startMethod,
String paramName, String paramName,
CodebaseContext context, CodebaseContext context,
Map<String, List<CallEdge>> callGraph) { Map<String, List<CallEdge>> callGraph,
List<String> stringCases = resolveStringCasesForParameter(startMethod, paramName, context, callGraph); Map<String, String> partialBindings) {
List<String> stringCases = resolveCasesWithParameterAliases(
startMethod, paramName, context, callGraph, partialBindings,
EntryPointBindingExpander::extractStringSwitchCasesForBindings);
if (!stringCases.isEmpty()) { if (!stringCases.isEmpty()) {
return stringCases; return stringCases;
} }
return resolveEnumValueOfCasesForParameter(startMethod, paramName, context, callGraph); return resolveCasesWithParameterAliases(
startMethod, paramName, context, callGraph, partialBindings,
EntryPointBindingExpander::extractEnumValueOfCasesForBindings);
} }
private static List<String> resolveStringCasesForParameter( @FunctionalInterface
String startMethod, private interface ParameterCaseExtractor {
List<String> extract(
String methodFqn,
String paramName,
CodebaseContext context,
Map<String, String> partialBindings);
}
private static List<String> extractStringSwitchCasesForBindings(
String methodFqn,
String paramName, String paramName,
CodebaseContext context, CodebaseContext context,
Map<String, List<CallEdge>> callGraph) { Map<String, String> partialBindings) {
ArrayDeque<String> queue = new ArrayDeque<>(); return extractStringSwitchCases(methodFqn, paramName, context);
}
private static List<String> extractEnumValueOfCasesForBindings(
String methodFqn,
String paramName,
CodebaseContext context,
Map<String, String> partialBindings) {
return extractEnumValueOfCases(methodFqn, paramName, context, partialBindings);
}
private record ParameterAliasState(String methodFqn, String paramName) {
}
private static List<String> resolveCasesWithParameterAliases(
String startMethod,
String entryParamName,
CodebaseContext context,
Map<String, List<CallEdge>> callGraph,
Map<String, String> partialBindings,
ParameterCaseExtractor extractor) {
ArrayDeque<ParameterAliasState> queue = new ArrayDeque<>();
Set<String> visited = new HashSet<>(); Set<String> visited = new HashSet<>();
queue.add(startMethod); queue.add(new ParameterAliasState(startMethod, entryParamName));
while (!queue.isEmpty()) { while (!queue.isEmpty()) {
String methodFqn = queue.poll(); ParameterAliasState state = queue.poll();
if (!visited.add(methodFqn)) { String visitKey = state.methodFqn() + "#" + state.paramName();
if (!visited.add(visitKey)) {
continue; continue;
} }
if (visited.size() > 12) { if (visited.size() > 24) {
break; break;
} }
List<String> localCases = extractStringSwitchCases(methodFqn, paramName, context); List<String> localCases = extractor.extract(
state.methodFqn(), state.paramName(), context, partialBindings);
if (!localCases.isEmpty()) { if (!localCases.isEmpty()) {
return localCases; return localCases;
} }
List<CallEdge> edges = callGraph.get(methodFqn); enqueueParameterAliasSuccessors(state, context, callGraph, partialBindings, queue);
if (edges == null) {
continue;
}
for (CallEdge edge : edges) {
if (edge.getTargetMethod() != null) {
queue.add(edge.getTargetMethod());
}
}
} }
return List.of(); return List.of();
} }
private static List<String> resolveEnumValueOfCasesForParameter( private static void enqueueParameterAliasSuccessors(
String startMethod, ParameterAliasState state,
String paramName,
CodebaseContext context, CodebaseContext context,
Map<String, List<CallEdge>> callGraph) { Map<String, List<CallEdge>> callGraph,
ArrayDeque<String> queue = new ArrayDeque<>(); Map<String, String> partialBindings,
Set<String> visited = new HashSet<>(); ArrayDeque<ParameterAliasState> queue) {
queue.add(startMethod); List<CallEdge> edges = callGraph.get(state.methodFqn());
while (!queue.isEmpty()) { if (edges == null) {
String methodFqn = queue.poll(); return;
if (!visited.add(methodFqn)) { }
for (CallEdge edge : edges) {
if (edge.getTargetMethod() == null || !isEdgeCompatibleWithBindings(edge, partialBindings)) {
continue; continue;
} }
if (visited.size() > 12) { List<String> args = edge.getArguments();
break; if (args == null || args.isEmpty()) {
}
List<String> localCases = extractEnumValueOfCases(methodFqn, paramName, context);
if (!localCases.isEmpty()) {
return localCases;
}
List<CallEdge> edges = callGraph.get(methodFqn);
if (edges == null) {
continue; continue;
} }
for (CallEdge edge : edges) { List<String> targetParamNames = getParameterNames(edge.getTargetMethod(), context);
if (edge.getTargetMethod() != null) { if (targetParamNames == null) {
queue.add(edge.getTargetMethod()); continue;
}
int limit = Math.min(args.size(), targetParamNames.size());
for (int i = 0; i < limit; i++) {
if (!argumentForwardsParameter(args.get(i), state.paramName())) {
continue;
} }
queue.add(new ParameterAliasState(edge.getTargetMethod(), targetParamNames.get(i)));
} }
} }
return List.of();
} }
static List<String> extractEnumValueOfCases(String methodFqn, String paramName, CodebaseContext context) { private static boolean isEdgeCompatibleWithBindings(CallEdge edge, Map<String, String> partialBindings) {
if (partialBindings == null || partialBindings.isEmpty()) {
return true;
}
String constraint = edge.getConstraint();
if (constraint == null || constraint.isBlank()) {
return true;
}
return BooleanConstraintEvaluator.isCompatibleWithBindings(constraint, partialBindings);
}
private static boolean argumentForwardsParameter(String argument, String paramName) {
if (argument == null || paramName == null) {
return false;
}
String trimmed = argument.trim();
if (paramName.equals(trimmed)) {
return true;
}
return ("this." + paramName).equals(trimmed);
}
private static List<String> getParameterNames(String methodFqn, CodebaseContext context) {
MethodDeclaration method = findMethodDeclaration(methodFqn, context);
if (method == null) {
return null;
}
List<String> names = new ArrayList<>();
for (Object paramObj : method.parameters()) {
if (paramObj instanceof SingleVariableDeclaration param) {
names.add(param.getName().getIdentifier());
}
}
return names;
}
static List<String> extractEnumValueOfCases(
String methodFqn,
String paramName,
CodebaseContext context,
Map<String, String> partialBindings) {
MethodDeclaration method = findMethodDeclaration(methodFqn, context); MethodDeclaration method = findMethodDeclaration(methodFqn, context);
if (method == null || method.getBody() == null || context == null) { if (method == null || method.getBody() == null || context == null) {
return List.of(); return List.of();
@@ -363,6 +437,9 @@ public final class EntryPointBindingExpander {
if (!argumentReferencesParameter(argument, paramName)) { if (!argumentReferencesParameter(argument, paramName)) {
return super.visit(node); return super.visit(node);
} }
if (!isValueOfSiteCompatibleWithBindings(node, partialBindings)) {
return super.visit(node);
}
String enumType = resolveValueOfEnumType(node, context); String enumType = resolveValueOfEnumType(node, context);
if (enumType != null) { if (enumType != null) {
enumTypes.add(enumType); enumTypes.add(enumType);
@@ -388,6 +465,19 @@ public final class EntryPointBindingExpander {
return List.copyOf(pathValues); return List.copyOf(pathValues);
} }
private static boolean isValueOfSiteCompatibleWithBindings(
MethodInvocation valueOfInvocation,
Map<String, String> partialBindings) {
if (partialBindings == null || partialBindings.isEmpty()) {
return true;
}
String branchConstraint = AstUtils.findConditionConstraint(valueOfInvocation);
if (branchConstraint == null || branchConstraint.isBlank()) {
return true;
}
return BooleanConstraintEvaluator.isCompatibleWithBindings(branchConstraint, partialBindings);
}
private static boolean argumentReferencesParameter(Expression argument, String paramName) { private static boolean argumentReferencesParameter(Expression argument, String paramName) {
if (argument instanceof SimpleName simpleName) { if (argument instanceof SimpleName simpleName) {
return paramName.equals(simpleName.getIdentifier()); return paramName.equals(simpleName.getIdentifier());

View File

@@ -40,6 +40,9 @@ public final class ExternalTriggerPolicy {
RestParamBinding binding = findRestParameterBinding(entryPoint, paramName, context); RestParamBinding binding = findRestParameterBinding(entryPoint, paramName, context);
if (binding != null) { if (binding != null) {
if (binding.pathOrQueryVariable() && !binding.enumType()) { if (binding.pathOrQueryVariable() && !binding.enumType()) {
if (binding.pathVariable() && !entryPointHasUnboundPlaceholders(entryPoint)) {
return false;
}
return true; return true;
} }
if (binding.requestBodyEnum()) { if (binding.requestBodyEnum()) {
@@ -81,9 +84,30 @@ public final class ExternalTriggerPolicy {
return false; return false;
} }
} }
if (entryPoint != null && entryPoint.getType() == EntryPoint.Type.REST
&& !entryPointHasUnboundPlaceholders(entryPoint)
&& MachineEnumCanonicalizer.isDynamicTriggerExpression(trigger.getEvent())) {
return false;
}
return trigger.isExternal(); return trigger.isExternal();
} }
private static boolean entryPointHasUnboundPlaceholders(EntryPoint entryPoint) {
if (entryPoint == null) {
return false;
}
if (entryPoint.getName() != null && entryPoint.getName().contains("{")) {
return true;
}
if (entryPoint.getMetadata() != null) {
String path = entryPoint.getMetadata().get("path");
if (path != null && path.contains("{")) {
return true;
}
}
return false;
}
private static String resolveRestEventParameterName(EntryPoint entryPoint, String resolvedEventParamName) { private static String resolveRestEventParameterName(EntryPoint entryPoint, String resolvedEventParamName) {
if (resolvedEventParamName != null && !resolvedEventParamName.isBlank()) { if (resolvedEventParamName != null && !resolvedEventParamName.isBlank()) {
return resolvedEventParamName; return resolvedEventParamName;

View File

@@ -437,6 +437,11 @@ public final class AnalysisCanonicalFormValidator {
if (chain.getMatchedTransitions() != null && !chain.getMatchedTransitions().isEmpty()) { if (chain.getMatchedTransitions() != null && !chain.getMatchedTransitions().isEmpty()) {
return; return;
} }
if (chain.getLinkResolution() == click.kamil.springstatemachineexporter.analysis.model.LinkResolution.NO_MATCH
|| chain.getLinkResolution()
== click.kamil.springstatemachineexporter.analysis.model.LinkResolution.UNRESOLVED_EXTERNAL) {
return;
}
MachineEnumCanonicalizer.TriggerEventKind eventKind = MachineEnumCanonicalizer.TriggerEventKind eventKind =
MachineEnumCanonicalizer.classifyTriggerEvent(trigger.getEvent()); MachineEnumCanonicalizer.classifyTriggerEvent(trigger.getEvent());

View File

@@ -51,14 +51,16 @@ class EnterpriseBooleanEnumPredicateExportTest {
.toList(); .toList();
assertThat(callChains).isNotEmpty(); assertThat(callChains).isNotEmpty();
JsonNode dynamicChain = callChains.stream() List<JsonNode> dispatchChains = callChains.stream()
.filter(chain -> chain.get("methodChain").toString().contains("OrderDispatcher.dispatch")) .filter(chain -> chain.get("methodChain").toString().contains("OrderDispatcher.dispatch"))
.findFirst() .toList();
.orElseThrow(() -> new AssertionError("missing OrderDispatcher.dispatch chain: " + callChains)); assertThat(dispatchChains).isNotEmpty();
JsonNode trigger = dynamicChain.get("triggerPoint"); List<String> polyEvents = dispatchChains.stream()
List<String> polyEvents = StreamSupport.stream(trigger.get("polymorphicEvents").spliterator(), false) .flatMap(chain -> StreamSupport.stream(
chain.get("triggerPoint").get("polymorphicEvents").spliterator(), false))
.map(JsonNode::asText) .map(JsonNode::asText)
.distinct()
.toList(); .toList();
assertThat(polyEvents) assertThat(polyEvents)
@@ -71,12 +73,23 @@ class EnterpriseBooleanEnumPredicateExportTest {
"com.example.order.OrderEvent.SHIP"); "com.example.order.OrderEvent.SHIP");
assertThat(polyEvents.size()).isLessThan(4); assertThat(polyEvents.size()).isLessThan(4);
List<JsonNode> matched = StreamSupport.stream(dynamicChain.get("matchedTransitions").spliterator(), false) for (JsonNode dispatchChain : dispatchChains) {
.toList(); long chainMatched = StreamSupport.stream(dispatchChain.get("matchedTransitions").spliterator(), false)
assertThat(matched.size()) .count();
assertThat(chainMatched)
.as("each dispatch chain must not cover all transitions")
.isLessThanOrEqualTo(transitionCount);
}
int matchedCount = dispatchChains.stream()
.mapToInt(chain -> StreamSupport.stream(chain.get("matchedTransitions").spliterator(), false)
.mapToInt(node -> 1)
.sum())
.sum();
assertThat(matchedCount)
.as("matchedTransitions must not cover every transition × every enum constant") .as("matchedTransitions must not cover every transition × every enum constant")
.isLessThanOrEqualTo(transitionCount); .isLessThan(transitionCount * dispatchChains.size());
Set<String> matchedEvents = matched.stream() Set<String> matchedEvents = dispatchChains.stream()
.flatMap(chain -> StreamSupport.stream(chain.get("matchedTransitions").spliterator(), false))
.map(node -> node.get("event").asText()) .map(node -> node.get("event").asText())
.collect(Collectors.toSet()); .collect(Collectors.toSet());
assertThat(matchedEvents) assertThat(matchedEvents)

View File

@@ -0,0 +1,33 @@
package click.kamil.springstatemachineexporter.analysis.resolver;
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
import click.kamil.springstatemachineexporter.analysis.resolver.StateMachineTypeResolver.MachineTypes;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
class MachineEnumCanonicalizerBoundValueOfTest {
@Test
void shouldExpandSingleBoundEventLiteralForValueOfTrigger() {
TriggerPoint trigger = TriggerPoint.builder()
.event("OrderEvent.valueOf(eventString.toUpperCase())")
.constraint("\"ORDER\".equalsIgnoreCase(machineType) && \"PAY\".equalsIgnoreCase(event)")
.external(true)
.build();
StateMachineTypeResolver.MachineTypes machineTypes =
new StateMachineTypeResolver.MachineTypes(
"com.example.order.OrderState",
"com.example.order.OrderEvent");
TriggerPoint expanded = MachineEnumCanonicalizer.expandBoundValueOfFromConstraints(
trigger, machineTypes, null);
assertThat(expanded.getPolymorphicEvents())
.containsExactly("com.example.order.OrderEvent.PAY");
assertThat(expanded.isExternal()).isFalse();
assertThat(expanded.isAmbiguous()).isFalse();
}
}

View File

@@ -10,19 +10,18 @@ import org.junit.jupiter.api.io.TempDir;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.stream.StreamSupport;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Regression for REST dispatcher chains: JSON round-trip must not re-infer all transition events * Regression for REST dispatcher chains: expanded concrete endpoints must not re-infer all
* for generic {@code {event}} endpoints. * transition events; unresolved {@code {event}} templates stay external.
*/ */
class EnterpriseDispatcherMatchedTransitionsRegressionTest { class EnterpriseDispatcherMatchedTransitionsRegressionTest {
private static final String TRANSITION_ENDPOINT = "POST /api/machine/{machineType}/transition/{event}";
@Test @Test
void astExportGenericTransitionEndpointShouldRemainUnlinked(@TempDir Path tempDir) throws Exception { void astExportExpandedTransitionEndpointsShouldNotOverLink(@TempDir Path tempDir) throws Exception {
Path enterprise = findProjectRoot().resolve("state_machines/state_machine_enterprise"); Path enterprise = findProjectRoot().resolve("state_machines/state_machine_enterprise");
ExportService exportService = new ExportService(List.of(new JsonExporter())); ExportService exportService = new ExportService(List.of(new JsonExporter()));
exportService.runExporter(enterprise, tempDir, List.of("json"), true, List.of(), null, null, exportService.runExporter(enterprise, tempDir, List.of("json"), true, List.of(), null, null,
@@ -30,25 +29,31 @@ class EnterpriseDispatcherMatchedTransitionsRegressionTest {
click.kamil.springstatemachineexporter.exporter.EnumFormat.fn); click.kamil.springstatemachineexporter.exporter.EnumFormat.fn);
JsonNode json = readMachineJson(tempDir, "OrderStateMachineConfiguration", new ObjectMapper()); JsonNode json = readMachineJson(tempDir, "OrderStateMachineConfiguration", new ObjectMapper());
JsonNode chain = findTransitionEndpointChain(json); int transitionCount = json.path("transitions").size();
assertThat(chain.path("triggerPoint").path("external").asBoolean()).isTrue(); StreamSupport.stream(json.path("metadata").path("callChains").spliterator(), false)
assertThat(chain.path("triggerPoint").path("polymorphicEvents").isArray()).isTrue(); .filter(chain -> chain.path("entryPoint").path("name").asText().contains("/transition/{event}"))
assertThat(chain.path("triggerPoint").path("polymorphicEvents")).isEmpty(); .forEach(chain -> {
JsonNode matched = chain.path("matchedTransitions"); JsonNode matched = chain.path("matchedTransitions");
assertThat(matched.isNull() || (matched.isArray() && matched.isEmpty())).isTrue(); assertThat(matched.isNull() || (matched.isArray() && matched.isEmpty())).isTrue();
assertThat(chain.path("linkResolution").asText()).isEqualTo("UNRESOLVED_EXTERNAL"); assertThat(chain.path("linkResolution").asText()).isEqualTo("UNRESOLVED_EXTERNAL");
});
JsonNode orderPay = findChainByEndpoint(json, "POST /api/machine/ORDER/transition/PAY");
assertThat(orderPay.path("linkResolution").asText()).isEqualTo("RESOLVED");
JsonNode matched = orderPay.path("matchedTransitions");
assertThat(matched.isArray()).isTrue();
assertThat(matched.size()).isLessThanOrEqualTo(transitionCount);
assertThat(matched.size()).isGreaterThan(0);
assertThat(matched.get(0).path("event").asText())
.contains("OrderEvent.PAY");
} }
private static JsonNode findTransitionEndpointChain(JsonNode machineJson) { private static JsonNode findChainByEndpoint(JsonNode machineJson, String endpointName) {
for (JsonNode chain : machineJson.path("metadata").path("callChains")) { return StreamSupport.stream(machineJson.path("metadata").path("callChains").spliterator(), false)
String name = chain.path("entryPoint").path("name").asText(); .filter(chain -> endpointName.equals(chain.path("entryPoint").path("name").asText()))
if (TRANSITION_ENDPOINT.equals(name) .findFirst()
|| (name.contains("/transition/{event}") && name.contains("POST /api/machine/"))) { .orElseThrow(() -> new IllegalStateException("chain not found for " + endpointName));
return chain;
}
}
throw new IllegalStateException("transition endpoint chain not found");
} }
private static JsonNode readMachineJson(Path outputDir, String configBaseName, ObjectMapper mapper) private static JsonNode readMachineJson(Path outputDir, String configBaseName, ObjectMapper mapper)

View File

@@ -0,0 +1,68 @@
package click.kamil.springstatemachineexporter.analysis.service;
import click.kamil.springstatemachineexporter.exporter.JsonExporter;
import click.kamil.springstatemachineexporter.service.ExportService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
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.List;
import java.util.stream.StreamSupport;
import static org.assertj.core.api.Assertions.assertThat;
/**
* When path bindings prove machine type and event, expanded REST endpoints should link;
* the unresolved generic template remains external.
*/
class EnterpriseExpandedGenericEndpointLinkingTest {
private static final String ORDER_PAY = "POST /api/machine/ORDER/transition/PAY";
@Test
void astExportExpandedOrderPayEndpointShouldLink(@TempDir Path tempDir) throws Exception {
Path enterprise = findProjectRoot().resolve("state_machines/state_machine_enterprise");
ExportService exportService = new ExportService(List.of(new JsonExporter()));
exportService.runExporter(enterprise, tempDir, List.of("json"), true, List.of(), null, null,
click.kamil.springstatemachineexporter.exporter.EnumFormat.fn,
click.kamil.springstatemachineexporter.exporter.EnumFormat.fn);
JsonNode json = readMachineJson(tempDir, "OrderStateMachineConfiguration", new ObjectMapper());
JsonNode expandedPayChain = findChainByEndpoint(json, ORDER_PAY);
assertThat(expandedPayChain.path("linkResolution").asText()).isEqualTo("RESOLVED");
assertThat(expandedPayChain.path("matchedTransitions").isArray()).isTrue();
assertThat(expandedPayChain.path("matchedTransitions")).isNotEmpty();
}
private static JsonNode findChainByEndpoint(JsonNode machineJson, String endpointName) {
return StreamSupport.stream(machineJson.path("metadata").path("callChains").spliterator(), false)
.filter(chain -> endpointName.equals(chain.path("entryPoint").path("name").asText()))
.findFirst()
.orElseThrow(() -> new IllegalStateException("chain not found for " + endpointName));
}
private static JsonNode readMachineJson(Path outputDir, String configBaseName, ObjectMapper mapper)
throws Exception {
Path machineDir;
try (var stream = Files.list(outputDir)) {
machineDir = stream
.filter(Files::isDirectory)
.filter(path -> path.getFileName().toString().endsWith(configBaseName))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No output for " + configBaseName));
}
return mapper.readTree(machineDir.resolve(machineDir.getFileName() + ".json").toFile());
}
private static Path findProjectRoot() {
Path current = Path.of(".").toAbsolutePath();
while (current != null && !Files.exists(current.resolve("settings.gradle"))) {
current = current.getParent();
}
return current;
}
}

View File

@@ -244,4 +244,130 @@ class EntryPointBindingExpanderTest {
assertThat(EntryPointBindingExpander.withResolvedPath(entryPoint, variants.get(0)).getName()) assertThat(EntryPointBindingExpander.withResolvedPath(entryPoint, variants.get(0)).getName())
.isEqualTo("POST /api/order/PAY"); .isEqualTo("POST /api/order/PAY");
} }
@Test
void shouldExpandRenamedEventThroughDispatcherWhenMachineTypeIsBound(@TempDir Path tempDir) throws Exception {
String source = """
package com.example;
public class MachineController {
StateMachineDispatcher dispatcher;
public void transition(String machineType, String event) {
dispatcher.dispatch(machineType, event);
}
}
class StateMachineDispatcher {
void dispatch(String machineType, String eventString) {
if ("ORDER".equalsIgnoreCase(machineType)) {
fireOrder(eventString);
} else if ("DOCUMENT".equalsIgnoreCase(machineType)) {
fireDocument(eventString);
}
}
void fireOrder(String eventString) {
OrderEvent.valueOf(eventString.toUpperCase());
}
void fireDocument(String eventString) {
DocumentEvent.valueOf(eventString.toUpperCase());
}
}
enum OrderEvent { PAY, SHIP }
enum DocumentEvent { SUBMIT, APPROVE }
""";
Files.writeString(tempDir.resolve("App.java"), source);
CodebaseContext context = new CodebaseContext();
context.setResolveBindings(true);
context.scan(tempDir);
HeuristicCallGraphEngine engine = new HeuristicCallGraphEngine(context);
Map<String, List<click.kamil.springstatemachineexporter.analysis.model.CallEdge>> graph = engine.buildCallGraph();
EntryPoint entryPoint = EntryPoint.builder()
.className("com.example.MachineController")
.methodName("transition")
.name("POST /api/machine/{machineType}/transition/{event}")
.parameters(List.of(
EntryPoint.Parameter.builder()
.name("machineType")
.type("String")
.annotations(List.of("PathVariable"))
.build(),
EntryPoint.Parameter.builder()
.name("event")
.type("String")
.annotations(List.of("PathVariable"))
.build()))
.build();
List<Map<String, String>> variants =
EntryPointBindingExpander.expandPathVariableBindings(entryPoint, context, graph);
assertThat(variants).anySatisfy(variant -> {
assertThat(variant).containsEntry("machineType", "ORDER");
assertThat(variant.get("event")).isIn("PAY", "SHIP");
});
assertThat(EntryPointBindingExpander.withResolvedPath(
entryPoint, Map.of("machineType", "ORDER", "event", "PAY")).getName())
.isEqualTo("POST /api/machine/ORDER/transition/PAY");
}
@Test
void shouldExpandRenamedEventFromInlineValueOfWhenMachineTypeIsBound(@TempDir Path tempDir) throws Exception {
String source = """
package com.example;
public class MachineController {
StateMachineDispatcher dispatcher;
public void transition(String machineType, String event) {
dispatcher.dispatch(machineType, event);
}
}
class StateMachineDispatcher {
void dispatch(String machineType, String eventString) {
if ("ORDER".equalsIgnoreCase(machineType)) {
OrderEvent event = OrderEvent.valueOf(eventString.toUpperCase());
send(event);
} else if ("DOCUMENT".equalsIgnoreCase(machineType)) {
DocumentEvent event = DocumentEvent.valueOf(eventString.toUpperCase());
send(event);
}
}
void send(OrderEvent event) {}
void send(DocumentEvent event) {}
}
enum OrderEvent { PAY, SHIP }
enum DocumentEvent { SUBMIT, APPROVE }
""";
Files.writeString(tempDir.resolve("App.java"), source);
CodebaseContext context = new CodebaseContext();
context.setResolveBindings(true);
context.scan(tempDir);
HeuristicCallGraphEngine engine = new HeuristicCallGraphEngine(context);
Map<String, List<click.kamil.springstatemachineexporter.analysis.model.CallEdge>> graph = engine.buildCallGraph();
EntryPoint entryPoint = EntryPoint.builder()
.className("com.example.MachineController")
.methodName("transition")
.name("POST /api/machine/{machineType}/transition/{event}")
.parameters(List.of(
EntryPoint.Parameter.builder()
.name("machineType")
.type("String")
.annotations(List.of("PathVariable"))
.build(),
EntryPoint.Parameter.builder()
.name("event")
.type("String")
.annotations(List.of("PathVariable"))
.build()))
.build();
List<Map<String, String>> variants =
EntryPointBindingExpander.expandPathVariableBindings(entryPoint, context, graph);
assertThat(variants.stream().anyMatch(variant ->
"ORDER".equals(variant.get("machineType"))
&& List.of("PAY", "SHIP").contains(variant.get("event")))).isTrue();
}
} }

View File

@@ -72,6 +72,33 @@ class ExternalTriggerPolicyTest {
entryPoint, trigger, "com.example.Api.transition", "event", context)).isFalse(); entryPoint, trigger, "com.example.Api.transition", "event", context)).isFalse();
} }
@Test
void concreteResolvedPathVariableEndpointShouldBeInternal() {
EntryPoint entryPoint = EntryPoint.builder()
.type(EntryPoint.Type.REST)
.name("POST /api/machine/ORDER/transition/PAY")
.className("com.example.Api")
.methodName("transition")
.parameters(List.of(
EntryPoint.Parameter.builder()
.name("machineType")
.type("String")
.annotations(List.of("PathVariable"))
.build(),
EntryPoint.Parameter.builder()
.name("event")
.type("String")
.annotations(List.of("PathVariable"))
.build()))
.build();
TriggerPoint trigger = TriggerPoint.builder()
.event("OrderEvent.valueOf(eventString.toUpperCase())")
.build();
assertThat(ExternalTriggerPolicy.isExternalFromSource(
entryPoint, trigger, "com.example.Api.transition", "event", null)).isFalse();
}
@Test @Test
void requestBodyEnumShouldBeInternal(@TempDir Path tempDir) throws Exception { void requestBodyEnumShouldBeInternal(@TempDir Path tempDir) throws Exception {
String source = """ String source = """

View File

@@ -169,12 +169,12 @@
} ] } ]
}, { }, {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/ORDER/transition/{event}", "name" : "POST /api/machine/ORDER/transition/PAY",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/ORDER/transition/{event}", "path" : "/api/machine/ORDER/transition/PAY",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -192,12 +192,12 @@
} ] } ]
}, { }, {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/{event}", "name" : "POST /api/machine/ORDER/transition/SHIP",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/DOCUMENT/transition/{event}", "path" : "/api/machine/ORDER/transition/SHIP",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -215,12 +215,127 @@
} ] } ]
}, { }, {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/USER/transition/{event}", "name" : "POST /api/machine/DOCUMENT/transition/SUBMIT",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/USER/transition/{event}", "path" : "/api/machine/DOCUMENT/transition/SUBMIT",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/APPROVE",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/APPROVE",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/REJECT",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/REJECT",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/REGISTER",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/REGISTER",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/VERIFY",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/VERIFY",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/SUSPEND",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/SUSPEND",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -380,12 +495,12 @@
}, { }, {
"entryPoint" : { "entryPoint" : {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/ORDER/transition/{event}", "name" : "POST /api/machine/ORDER/transition/PAY",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/ORDER/transition/{event}", "path" : "/api/machine/ORDER/transition/PAY",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -413,22 +528,65 @@
"sourceState" : null, "sourceState" : null,
"lineNumber" : 87, "lineNumber" : 87,
"polymorphicEvents" : [ ], "polymorphicEvents" : [ ],
"external" : true, "external" : false,
"constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)", "constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && \"PAY\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
"ambiguous" : false "ambiguous" : false
}, },
"contextMachineId" : null, "contextMachineId" : null,
"matchedTransitions" : null, "matchedTransitions" : null,
"linkResolution" : "UNRESOLVED_EXTERNAL" "linkResolution" : "NO_MATCH"
}, { }, {
"entryPoint" : { "entryPoint" : {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/{event}", "name" : "POST /api/machine/ORDER/transition/SHIP",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/DOCUMENT/transition/{event}", "path" : "/api/machine/ORDER/transition/SHIP",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "OrderEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : null,
"lineNumber" : 87,
"polymorphicEvents" : [ ],
"external" : false,
"constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && \"SHIP\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : null,
"linkResolution" : "NO_MATCH"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/SUBMIT",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/SUBMIT",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -453,25 +611,123 @@
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null, "sourceModule" : null,
"stateMachineId" : null, "stateMachineId" : null,
"sourceState" : null, "sourceState" : "click.kamil.enterprise.machines.document.DocumentState.DRAFT",
"lineNumber" : 87, "lineNumber" : 87,
"polymorphicEvents" : [ ], "polymorphicEvents" : [ "click.kamil.enterprise.machines.document.DocumentEvent.SUBMIT" ],
"external" : true, "external" : false,
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)", "constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"SUBMIT\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
"ambiguous" : false "ambiguous" : false
}, },
"contextMachineId" : null, "contextMachineId" : null,
"matchedTransitions" : null, "matchedTransitions" : [ {
"linkResolution" : "UNRESOLVED_EXTERNAL" "sourceState" : "click.kamil.enterprise.machines.document.DocumentState.DRAFT",
"targetState" : "click.kamil.enterprise.machines.document.DocumentState.IN_REVIEW",
"event" : "click.kamil.enterprise.machines.document.DocumentEvent.SUBMIT"
} ],
"linkResolution" : "RESOLVED"
}, { }, {
"entryPoint" : { "entryPoint" : {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/USER/transition/{event}", "name" : "POST /api/machine/DOCUMENT/transition/APPROVE",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/USER/transition/{event}", "path" : "/api/machine/DOCUMENT/transition/APPROVE",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "DocumentEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : "click.kamil.enterprise.machines.document.DocumentState.IN_REVIEW",
"lineNumber" : 87,
"polymorphicEvents" : [ "click.kamil.enterprise.machines.document.DocumentEvent.APPROVE" ],
"external" : false,
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"APPROVE\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : [ {
"sourceState" : "click.kamil.enterprise.machines.document.DocumentState.IN_REVIEW",
"targetState" : "click.kamil.enterprise.machines.document.DocumentState.APPROVED",
"event" : "click.kamil.enterprise.machines.document.DocumentEvent.APPROVE"
} ],
"linkResolution" : "RESOLVED"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/REJECT",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/REJECT",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "DocumentEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : "click.kamil.enterprise.machines.document.DocumentState.IN_REVIEW",
"lineNumber" : 87,
"polymorphicEvents" : [ "click.kamil.enterprise.machines.document.DocumentEvent.REJECT" ],
"external" : false,
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"REJECT\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : [ {
"sourceState" : "click.kamil.enterprise.machines.document.DocumentState.IN_REVIEW",
"targetState" : "click.kamil.enterprise.machines.document.DocumentState.DRAFT",
"event" : "click.kamil.enterprise.machines.document.DocumentEvent.REJECT"
} ],
"linkResolution" : "RESOLVED"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/REGISTER",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/REGISTER",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -499,13 +755,99 @@
"sourceState" : null, "sourceState" : null,
"lineNumber" : 87, "lineNumber" : 87,
"polymorphicEvents" : [ ], "polymorphicEvents" : [ ],
"external" : true, "external" : false,
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)", "constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"REGISTER\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
"ambiguous" : false "ambiguous" : false
}, },
"contextMachineId" : null, "contextMachineId" : null,
"matchedTransitions" : null, "matchedTransitions" : null,
"linkResolution" : "UNRESOLVED_EXTERNAL" "linkResolution" : "NO_MATCH"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/VERIFY",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/VERIFY",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "UserEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : null,
"lineNumber" : 87,
"polymorphicEvents" : [ ],
"external" : false,
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"VERIFY\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : null,
"linkResolution" : "NO_MATCH"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/SUSPEND",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/SUSPEND",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "UserEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : null,
"lineNumber" : 87,
"polymorphicEvents" : [ ],
"external" : false,
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"SUSPEND\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : null,
"linkResolution" : "NO_MATCH"
} ], } ],
"properties" : { "properties" : {
"default" : { } "default" : { }

View File

@@ -131,12 +131,12 @@
} ] } ]
}, { }, {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/ORDER/transition/{event}", "name" : "POST /api/machine/ORDER/transition/PAY",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/ORDER/transition/{event}", "path" : "/api/machine/ORDER/transition/PAY",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -154,12 +154,12 @@
} ] } ]
}, { }, {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/{event}", "name" : "POST /api/machine/ORDER/transition/SHIP",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/DOCUMENT/transition/{event}", "path" : "/api/machine/ORDER/transition/SHIP",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -177,12 +177,127 @@
} ] } ]
}, { }, {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/USER/transition/{event}", "name" : "POST /api/machine/DOCUMENT/transition/SUBMIT",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/USER/transition/{event}", "path" : "/api/machine/DOCUMENT/transition/SUBMIT",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/APPROVE",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/APPROVE",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/REJECT",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/REJECT",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/REGISTER",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/REGISTER",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/VERIFY",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/VERIFY",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/SUSPEND",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/SUSPEND",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -303,12 +418,12 @@
}, { }, {
"entryPoint" : { "entryPoint" : {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/ORDER/transition/{event}", "name" : "POST /api/machine/ORDER/transition/PAY",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/ORDER/transition/{event}", "path" : "/api/machine/ORDER/transition/PAY",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -333,25 +448,76 @@
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null, "sourceModule" : null,
"stateMachineId" : null, "stateMachineId" : null,
"sourceState" : null, "sourceState" : "click.kamil.enterprise.machines.order.OrderState.NEW",
"lineNumber" : 81, "lineNumber" : 81,
"polymorphicEvents" : [ ], "polymorphicEvents" : [ "click.kamil.enterprise.machines.order.OrderEvent.PAY" ],
"external" : true, "external" : false,
"constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && \"ORDER\".equalsIgnoreCase(machineType)", "constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && \"PAY\".equalsIgnoreCase(event) && \"ORDER\".equalsIgnoreCase(machineType)",
"ambiguous" : false "ambiguous" : false
}, },
"contextMachineId" : null, "contextMachineId" : null,
"matchedTransitions" : null, "matchedTransitions" : [ {
"linkResolution" : "UNRESOLVED_EXTERNAL" "sourceState" : "click.kamil.enterprise.machines.order.OrderState.NEW",
"targetState" : "click.kamil.enterprise.machines.order.OrderState.PENDING",
"event" : "click.kamil.enterprise.machines.order.OrderEvent.PAY"
} ],
"linkResolution" : "RESOLVED"
}, { }, {
"entryPoint" : { "entryPoint" : {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/{event}", "name" : "POST /api/machine/ORDER/transition/SHIP",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/DOCUMENT/transition/{event}", "path" : "/api/machine/ORDER/transition/SHIP",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "OrderEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : "click.kamil.enterprise.machines.order.OrderState.PENDING",
"lineNumber" : 81,
"polymorphicEvents" : [ "click.kamil.enterprise.machines.order.OrderEvent.SHIP" ],
"external" : false,
"constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && \"SHIP\".equalsIgnoreCase(event) && \"ORDER\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : [ {
"sourceState" : "click.kamil.enterprise.machines.order.OrderState.PENDING",
"targetState" : "click.kamil.enterprise.machines.order.OrderState.SHIPPED",
"event" : "click.kamil.enterprise.machines.order.OrderEvent.SHIP"
} ],
"linkResolution" : "RESOLVED"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/SUBMIT",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/SUBMIT",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -379,22 +545,108 @@
"sourceState" : null, "sourceState" : null,
"lineNumber" : 81, "lineNumber" : 81,
"polymorphicEvents" : [ ], "polymorphicEvents" : [ ],
"external" : true, "external" : false,
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"ORDER\".equalsIgnoreCase(machineType)", "constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"SUBMIT\".equalsIgnoreCase(event) && \"ORDER\".equalsIgnoreCase(machineType)",
"ambiguous" : false "ambiguous" : false
}, },
"contextMachineId" : null, "contextMachineId" : null,
"matchedTransitions" : null, "matchedTransitions" : null,
"linkResolution" : "UNRESOLVED_EXTERNAL" "linkResolution" : "NO_MATCH"
}, { }, {
"entryPoint" : { "entryPoint" : {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/USER/transition/{event}", "name" : "POST /api/machine/DOCUMENT/transition/APPROVE",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/USER/transition/{event}", "path" : "/api/machine/DOCUMENT/transition/APPROVE",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "DocumentEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : null,
"lineNumber" : 81,
"polymorphicEvents" : [ ],
"external" : false,
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"APPROVE\".equalsIgnoreCase(event) && \"ORDER\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : null,
"linkResolution" : "NO_MATCH"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/REJECT",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/REJECT",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "DocumentEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : null,
"lineNumber" : 81,
"polymorphicEvents" : [ ],
"external" : false,
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"REJECT\".equalsIgnoreCase(event) && \"ORDER\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : null,
"linkResolution" : "NO_MATCH"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/REGISTER",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/REGISTER",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -422,13 +674,99 @@
"sourceState" : null, "sourceState" : null,
"lineNumber" : 81, "lineNumber" : 81,
"polymorphicEvents" : [ ], "polymorphicEvents" : [ ],
"external" : true, "external" : false,
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"ORDER\".equalsIgnoreCase(machineType)", "constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"REGISTER\".equalsIgnoreCase(event) && \"ORDER\".equalsIgnoreCase(machineType)",
"ambiguous" : false "ambiguous" : false
}, },
"contextMachineId" : null, "contextMachineId" : null,
"matchedTransitions" : null, "matchedTransitions" : null,
"linkResolution" : "UNRESOLVED_EXTERNAL" "linkResolution" : "NO_MATCH"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/VERIFY",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/VERIFY",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "UserEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : null,
"lineNumber" : 81,
"polymorphicEvents" : [ ],
"external" : false,
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"VERIFY\".equalsIgnoreCase(event) && \"ORDER\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : null,
"linkResolution" : "NO_MATCH"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/SUSPEND",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/SUSPEND",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "UserEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : null,
"lineNumber" : 81,
"polymorphicEvents" : [ ],
"external" : false,
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"SUSPEND\".equalsIgnoreCase(event) && \"ORDER\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : null,
"linkResolution" : "NO_MATCH"
} ], } ],
"properties" : { "properties" : {
"default" : { } "default" : { }

View File

@@ -124,12 +124,12 @@
} ] } ]
}, { }, {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/ORDER/transition/{event}", "name" : "POST /api/machine/ORDER/transition/PAY",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/ORDER/transition/{event}", "path" : "/api/machine/ORDER/transition/PAY",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -147,12 +147,12 @@
} ] } ]
}, { }, {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/{event}", "name" : "POST /api/machine/ORDER/transition/SHIP",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/DOCUMENT/transition/{event}", "path" : "/api/machine/ORDER/transition/SHIP",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -170,12 +170,127 @@
} ] } ]
}, { }, {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/USER/transition/{event}", "name" : "POST /api/machine/DOCUMENT/transition/SUBMIT",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/USER/transition/{event}", "path" : "/api/machine/DOCUMENT/transition/SUBMIT",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/APPROVE",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/APPROVE",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/REJECT",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/REJECT",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/REGISTER",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/REGISTER",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/VERIFY",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/VERIFY",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
}, {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/SUSPEND",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/SUSPEND",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -292,12 +407,12 @@
}, { }, {
"entryPoint" : { "entryPoint" : {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/ORDER/transition/{event}", "name" : "POST /api/machine/ORDER/transition/PAY",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/ORDER/transition/{event}", "path" : "/api/machine/ORDER/transition/PAY",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -325,22 +440,65 @@
"sourceState" : null, "sourceState" : null,
"lineNumber" : 93, "lineNumber" : 93,
"polymorphicEvents" : [ ], "polymorphicEvents" : [ ],
"external" : true, "external" : false,
"constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)", "constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && \"PAY\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
"ambiguous" : false "ambiguous" : false
}, },
"contextMachineId" : null, "contextMachineId" : null,
"matchedTransitions" : null, "matchedTransitions" : null,
"linkResolution" : "UNRESOLVED_EXTERNAL" "linkResolution" : "NO_MATCH"
}, { }, {
"entryPoint" : { "entryPoint" : {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/{event}", "name" : "POST /api/machine/ORDER/transition/SHIP",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/DOCUMENT/transition/{event}", "path" : "/api/machine/ORDER/transition/SHIP",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "OrderEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : null,
"lineNumber" : 93,
"polymorphicEvents" : [ ],
"external" : false,
"constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && \"SHIP\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : null,
"linkResolution" : "NO_MATCH"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/SUBMIT",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/SUBMIT",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -368,22 +526,202 @@
"sourceState" : null, "sourceState" : null,
"lineNumber" : 93, "lineNumber" : 93,
"polymorphicEvents" : [ ], "polymorphicEvents" : [ ],
"external" : true, "external" : false,
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)", "constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"SUBMIT\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
"ambiguous" : false "ambiguous" : false
}, },
"contextMachineId" : null, "contextMachineId" : null,
"matchedTransitions" : null, "matchedTransitions" : null,
"linkResolution" : "UNRESOLVED_EXTERNAL" "linkResolution" : "NO_MATCH"
}, { }, {
"entryPoint" : { "entryPoint" : {
"type" : "REST", "type" : "REST",
"name" : "POST /api/machine/USER/transition/{event}", "name" : "POST /api/machine/DOCUMENT/transition/APPROVE",
"className" : "click.kamil.enterprise.web.StateMachineController", "className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition", "methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java", "sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : { "metadata" : {
"path" : "/api/machine/USER/transition/{event}", "path" : "/api/machine/DOCUMENT/transition/APPROVE",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "DocumentEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : null,
"lineNumber" : 93,
"polymorphicEvents" : [ ],
"external" : false,
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"APPROVE\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : null,
"linkResolution" : "NO_MATCH"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/DOCUMENT/transition/REJECT",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/DOCUMENT/transition/REJECT",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "DocumentEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : null,
"lineNumber" : 93,
"polymorphicEvents" : [ ],
"external" : false,
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"REJECT\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : null,
"linkResolution" : "NO_MATCH"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/REGISTER",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/REGISTER",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "UserEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : "click.kamil.enterprise.machines.user.UserState.GUEST",
"lineNumber" : 93,
"polymorphicEvents" : [ "click.kamil.enterprise.machines.user.UserEvent.REGISTER" ],
"external" : false,
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"REGISTER\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : [ {
"sourceState" : "click.kamil.enterprise.machines.user.UserState.GUEST",
"targetState" : "click.kamil.enterprise.machines.user.UserState.REGISTERED",
"event" : "click.kamil.enterprise.machines.user.UserEvent.REGISTER"
} ],
"linkResolution" : "RESOLVED"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/VERIFY",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/VERIFY",
"verb" : "POST"
},
"parameters" : [ {
"name" : "machineType",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "event",
"type" : "String",
"annotations" : [ "PathVariable" ]
}, {
"name" : "userId",
"type" : "String",
"annotations" : [ "RequestParam" ]
} ]
},
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
"triggerPoint" : {
"event" : "UserEvent.valueOf(eventString.toUpperCase())",
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
"methodName" : "dispatch",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
"sourceModule" : null,
"stateMachineId" : null,
"sourceState" : "click.kamil.enterprise.machines.user.UserState.REGISTERED",
"lineNumber" : 93,
"polymorphicEvents" : [ "click.kamil.enterprise.machines.user.UserEvent.VERIFY" ],
"external" : false,
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"VERIFY\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
"ambiguous" : false
},
"contextMachineId" : null,
"matchedTransitions" : [ {
"sourceState" : "click.kamil.enterprise.machines.user.UserState.REGISTERED",
"targetState" : "click.kamil.enterprise.machines.user.UserState.VERIFIED",
"event" : "click.kamil.enterprise.machines.user.UserEvent.VERIFY"
} ],
"linkResolution" : "RESOLVED"
}, {
"entryPoint" : {
"type" : "REST",
"name" : "POST /api/machine/USER/transition/SUSPEND",
"className" : "click.kamil.enterprise.web.StateMachineController",
"methodName" : "transition",
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
"metadata" : {
"path" : "/api/machine/USER/transition/SUSPEND",
"verb" : "POST" "verb" : "POST"
}, },
"parameters" : [ { "parameters" : [ {
@@ -411,13 +749,13 @@
"sourceState" : null, "sourceState" : null,
"lineNumber" : 93, "lineNumber" : 93,
"polymorphicEvents" : [ ], "polymorphicEvents" : [ ],
"external" : true, "external" : false,
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)", "constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"SUSPEND\".equalsIgnoreCase(event) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
"ambiguous" : false "ambiguous" : false
}, },
"contextMachineId" : null, "contextMachineId" : null,
"matchedTransitions" : null, "matchedTransitions" : null,
"linkResolution" : "UNRESOLVED_EXTERNAL" "linkResolution" : "NO_MATCH"
} ], } ],
"properties" : { "properties" : {
"default" : { } "default" : { }