Link REST endpoints via source-proven call-graph scoping and branch expansion.
Scope machines from call-chain type evidence, expand path bindings from switch/if literals, unify external trigger policy, add linkResolution export metadata, and built-in trigger detection without hints.json. Co-authored-by: Cursor <cursoragent@cursor.com>
@@ -1,9 +1,14 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.enricher;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
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.Map;
|
||||
|
||||
@@ -12,77 +17,121 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class MachineScopeFilterEntryPointTest {
|
||||
|
||||
@Test
|
||||
void shouldKeepOrderEndpointsOnOrderMachineOnly() {
|
||||
void shouldDeriveScopedEntryPointsFromCallChainsAndKeepGenericPathVariables() {
|
||||
EntryPoint orderPay = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/orders/pay")
|
||||
.className("click.kamil.examples.statemachine.layered.web.OrderController")
|
||||
.methodName("pay")
|
||||
.metadata(Map.of("path", "/api/orders/pay"))
|
||||
.name("POST /api/machine/order/pay")
|
||||
.className("com.example.StateMachineController")
|
||||
.methodName("payOrder")
|
||||
.build();
|
||||
EntryPoint documentSubmit = EntryPoint.builder()
|
||||
EntryPoint genericTransition = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/documents/submit")
|
||||
.className("click.kamil.examples.statemachine.layered.web.DocumentController")
|
||||
.methodName("submit")
|
||||
.metadata(Map.of("path", "/api/documents/submit"))
|
||||
.build();
|
||||
EntryPoint genericCommand = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/commands/{commandKey}")
|
||||
.className("click.kamil.examples.statemachine.layered.web.GenericCommandController")
|
||||
.methodName("execute")
|
||||
.metadata(Map.of("path", "/api/commands/{commandKey}"))
|
||||
.name("POST /api/machine/{machineType}/transition/{event}")
|
||||
.className("com.example.StateMachineController")
|
||||
.methodName("transition")
|
||||
.metadata(Map.of("path", "/api/machine/{machineType}/transition/{event}"))
|
||||
.build();
|
||||
|
||||
CallChain payChain = CallChain.builder()
|
||||
.entryPoint(orderPay)
|
||||
.triggerPoint(TriggerPoint.builder()
|
||||
.event("com.example.OrderEvent.PAY")
|
||||
.eventTypeFqn("com.example.OrderEvent")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
List<EntryPoint> scoped = EntryPointScopeResolver.scopeFromCallChains(
|
||||
List.of(payChain),
|
||||
List.of(orderPay, genericTransition));
|
||||
|
||||
assertThat(scoped).extracting(EntryPoint::getName)
|
||||
.containsExactlyInAnyOrder(
|
||||
"POST /api/machine/order/pay",
|
||||
"POST /api/machine/{machineType}/transition/{event}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldScopeEnterpriseDedicatedPayEndpointToOrderMachine(@TempDir Path tempDir) throws Exception {
|
||||
writeEnterpriseWebLayer(tempDir);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
EntryPoint payOrder = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/machine/order/pay")
|
||||
.className("com.example.StateMachineController")
|
||||
.methodName("payOrder")
|
||||
.metadata(Map.of("path", "/api/machine/order/pay"))
|
||||
.build();
|
||||
EntryPoint submitDocument = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/machine/document/submit")
|
||||
.className("com.example.StateMachineController")
|
||||
.methodName("submitDocument")
|
||||
.metadata(Map.of("path", "/api/machine/document/submit"))
|
||||
.build();
|
||||
|
||||
List<EntryPoint> orderScoped = MachineScopeFilter.filterEntryPointsForMachine(
|
||||
List.of(orderPay, documentSubmit, genericCommand),
|
||||
"click.kamil.examples.statemachine.layered.order.config.StandardOrderStateMachineConfiguration",
|
||||
List.of(payOrder, submitDocument),
|
||||
"com.example.OrderStateMachineConfiguration",
|
||||
context);
|
||||
|
||||
assertThat(orderScoped).extracting(EntryPoint::getName)
|
||||
.contains("POST /api/orders/pay", "POST /api/commands/{commandKey}")
|
||||
.doesNotContain("POST /api/documents/submit");
|
||||
.containsExactly("POST /api/machine/order/pay");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldKeepDedicatedOrderEndpointOnStandardOrderMachineInMultiModuleCodebase() {
|
||||
EntryPoint orderPay = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/orders/pay")
|
||||
.className("click.kamil.examples.statemachine.layered.web.OrderController")
|
||||
.methodName("pay")
|
||||
.metadata(Map.of("path", "/api/orders/pay"))
|
||||
.build();
|
||||
void shouldExcludeDocumentDedicatedEndpointFromOrderMachine(@TempDir Path tempDir) throws Exception {
|
||||
writeEnterpriseWebLayer(tempDir);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
List<EntryPoint> scoped = MachineScopeFilter.filterEntryPointsForMachine(
|
||||
List.of(orderPay),
|
||||
"click.kamil.examples.statemachine.layered.order.config.StandardOrderStateMachineConfiguration",
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
EntryPoint submitDocument = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/machine/document/submit")
|
||||
.className("com.example.StateMachineController")
|
||||
.methodName("submitDocument")
|
||||
.metadata(Map.of("path", "/api/machine/document/submit"))
|
||||
.build();
|
||||
|
||||
List<EntryPoint> orderScoped = MachineScopeFilter.filterEntryPointsForMachine(
|
||||
List.of(submitDocument),
|
||||
"com.example.OrderStateMachineConfiguration",
|
||||
context);
|
||||
|
||||
assertThat(scoped).extracting(EntryPoint::getName)
|
||||
.containsExactly("POST /api/orders/pay");
|
||||
assertThat(orderScoped).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldKeepOrdersPathOnNonDomainNamedMachineConfig() {
|
||||
EntryPoint ordersSubmit = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/v2/orders/submit")
|
||||
.className("click.kamil.examples.statemachine.inheritance.api.OrderControllerImpl")
|
||||
.methodName("submitOrder")
|
||||
.metadata(Map.of("path", "/api/v2/orders/submit"))
|
||||
.build();
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
List<EntryPoint> scoped = MachineScopeFilter.filterEntryPointsForMachine(
|
||||
List.of(ordersSubmit),
|
||||
"click.kamil.examples.statemachine.inheritance.config.InheritanceStateMachineConfig",
|
||||
context);
|
||||
|
||||
assertThat(scoped).extracting(EntryPoint::getName)
|
||||
.containsExactly("POST /api/v2/orders/submit");
|
||||
private static void writeEnterpriseWebLayer(Path tempDir) throws Exception {
|
||||
Files.writeString(tempDir.resolve("App.java"), """
|
||||
package com.example;
|
||||
public class StateMachineController {
|
||||
private final StateMachineDispatcher dispatcher = new StateMachineDispatcher();
|
||||
public void payOrder() { dispatcher.payOrder(); }
|
||||
public void submitDocument() { dispatcher.submitDocument(); }
|
||||
}
|
||||
class StateMachineDispatcher {
|
||||
void payOrder() {
|
||||
org.springframework.statemachine.StateMachine<OrderState, OrderEvent> machine = null;
|
||||
machine.sendEvent(OrderEvent.PAY);
|
||||
}
|
||||
void submitDocument() {
|
||||
org.springframework.statemachine.StateMachine<DocumentState, DocumentEvent> machine = null;
|
||||
machine.sendEvent(DocumentEvent.SUBMIT);
|
||||
}
|
||||
}
|
||||
enum OrderEvent { PAY }
|
||||
enum OrderState { NEW, PAID }
|
||||
enum DocumentEvent { SUBMIT }
|
||||
enum DocumentState { DRAFT }
|
||||
class OrderStateMachineConfiguration
|
||||
extends org.springframework.statemachine.config.StateMachineConfigurerAdapter<OrderState, OrderEvent> {}
|
||||
class DocumentStateMachineConfiguration
|
||||
extends org.springframework.statemachine.config.StateMachineConfigurerAdapter<DocumentState, DocumentEvent> {}
|
||||
""");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ 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.EntryPoint;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.LinkResolution;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
import click.kamil.springstatemachineexporter.model.Event;
|
||||
import click.kamil.springstatemachineexporter.model.State;
|
||||
@@ -42,6 +44,74 @@ class TransitionLinkerEnricherTest {
|
||||
assertThat(result.getMetadata().getCallChains().get(0).getMatchedTransitions()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExportResolvedLinkResolutionForDedicatedLiteralEndpoint() {
|
||||
Transition payT = new Transition();
|
||||
payT.setSourceStates(List.of(State.of("NEW", "OrderState.NEW")));
|
||||
payT.setTargetStates(List.of(State.of("PAID", "OrderState.PAID")));
|
||||
payT.setEvent(Event.of("OrderEvent.PAY", "com.example.OrderEvent.PAY"));
|
||||
|
||||
CallChain chain = CallChain.builder()
|
||||
.entryPoint(EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/order/pay")
|
||||
.className("com.example.Api")
|
||||
.methodName("pay")
|
||||
.build())
|
||||
.triggerPoint(TriggerPoint.builder()
|
||||
.event("OrderEvent.PAY")
|
||||
.polymorphicEvents(List.of("OrderEvent.PAY"))
|
||||
.external(false)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
.name("OrderStateMachineConfig")
|
||||
.transitions(List.of(payT))
|
||||
.metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
|
||||
.build();
|
||||
|
||||
enricher.enrich(result, null, null);
|
||||
|
||||
CallChain updated = result.getMetadata().getCallChains().get(0);
|
||||
assertThat(updated.getLinkResolution()).isEqualTo(LinkResolution.RESOLVED);
|
||||
assertThat(updated.getMatchedTransitions()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExportUnresolvedExternalForGenericPathVariableEndpoint() {
|
||||
CallChain chain = CallChain.builder()
|
||||
.entryPoint(EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/machine/{machineType}/transition/{event}")
|
||||
.className("com.example.Api")
|
||||
.methodName("transition")
|
||||
.build())
|
||||
.triggerPoint(TriggerPoint.builder()
|
||||
.event("eventString.toUpperCase()")
|
||||
.external(true)
|
||||
.ambiguous(true)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
Transition payT = new Transition();
|
||||
payT.setSourceStates(List.of(State.of("NEW", "OrderState.NEW")));
|
||||
payT.setTargetStates(List.of(State.of("PAID", "OrderState.PAID")));
|
||||
payT.setEvent(Event.of("OrderEvent.PAY", "com.example.OrderEvent.PAY"));
|
||||
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
.name("OrderStateMachineConfig")
|
||||
.transitions(List.of(payT))
|
||||
.metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
|
||||
.build();
|
||||
|
||||
enricher.enrich(result, null, null);
|
||||
|
||||
CallChain updated = result.getMetadata().getCallChains().get(0);
|
||||
assertThat(updated.getLinkResolution()).isEqualTo(LinkResolution.UNRESOLVED_EXTERNAL);
|
||||
assertThat(updated.getMatchedTransitions()).isNullOrEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldLinkWhenSymbolicPolymorphicEventsExpandToMachineEnumConstants() {
|
||||
Transition payT = new Transition();
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
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 TransitionLinkerMultiSourceStateTest {
|
||||
|
||||
@Test
|
||||
void shouldLinkEachSourceStatePairWithoutCrossMultiplication() {
|
||||
TriggerPoint trigger = TriggerPoint.builder()
|
||||
.event("com.example.OrderEvent.CANCEL")
|
||||
.sourceState("com.example.OrderState.PENDING")
|
||||
.build();
|
||||
CallChain chain = CallChain.builder()
|
||||
.entryPoint(click.kamil.springstatemachineexporter.analysis.model.EntryPoint.builder()
|
||||
.type(click.kamil.springstatemachineexporter.analysis.model.EntryPoint.Type.REST)
|
||||
.name("POST /cancel")
|
||||
.className("com.example.Api")
|
||||
.methodName("cancel")
|
||||
.build())
|
||||
.triggerPoint(trigger)
|
||||
.methodChain(List.of("com.example.Api.cancel", "com.example.Service.fire"))
|
||||
.build();
|
||||
|
||||
Transition fromPending = transition(
|
||||
"com.example.OrderEvent.CANCEL",
|
||||
"com.example.OrderState.PENDING",
|
||||
"com.example.OrderState.CANCELLED");
|
||||
Transition fromPaid = transition(
|
||||
"com.example.OrderEvent.CANCEL",
|
||||
"com.example.OrderState.PAID",
|
||||
"com.example.OrderState.CANCELLED");
|
||||
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
.name("com.example.config.OrderStateMachineConfiguration")
|
||||
.stateTypeFqn("com.example.OrderState")
|
||||
.eventTypeFqn("com.example.OrderEvent")
|
||||
.transitions(List.of(fromPending, fromPaid))
|
||||
.metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
|
||||
.build();
|
||||
|
||||
new TransitionLinkerEnricher().enrich(result, null, null);
|
||||
|
||||
assertThat(result.getMetadata().getCallChains().get(0).getMatchedTransitions())
|
||||
.hasSize(1)
|
||||
.first()
|
||||
.satisfies(mt -> {
|
||||
assertThat(mt.getSourceState()).isEqualTo("com.example.OrderState.PENDING");
|
||||
assertThat(mt.getEvent()).isEqualTo("com.example.OrderEvent.CANCEL");
|
||||
});
|
||||
}
|
||||
|
||||
private static Transition transition(String event, String source, String target) {
|
||||
Transition transition = new Transition();
|
||||
transition.setEvent(Event.of(event, event));
|
||||
transition.setSourceStates(List.of(
|
||||
State.of(source, source),
|
||||
State.of("com.example.OrderState.OTHER", "com.example.OrderState.OTHER")));
|
||||
transition.setTargetStates(List.of(State.of(target, target)));
|
||||
return transition;
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,65 @@ class HeuristicBeanResolutionEngineRoutingTest {
|
||||
context)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void sharedServiceWithProvenOrderTypesShouldOnlyRouteToOrderMachine(@TempDir Path tempDir) throws Exception {
|
||||
Files.writeString(tempDir.resolve("SharedDispatcher.java"), """
|
||||
package com.example;
|
||||
public class SharedDispatcher {
|
||||
void payOrder() {
|
||||
org.springframework.statemachine.StateMachine<OrderState, OrderEvent> machine = null;
|
||||
machine.sendEvent(OrderEvent.PAY);
|
||||
}
|
||||
void submitDocument() {
|
||||
org.springframework.statemachine.StateMachine<DocumentState, DocumentEvent> machine = null;
|
||||
machine.sendEvent(DocumentEvent.SUBMIT);
|
||||
}
|
||||
}
|
||||
enum OrderEvent { PAY }
|
||||
enum OrderState { NEW, PAID }
|
||||
enum DocumentEvent { SUBMIT }
|
||||
enum DocumentState { DRAFT }
|
||||
class OrderStateMachineConfiguration
|
||||
extends org.springframework.statemachine.config.StateMachineConfigurerAdapter<OrderState, OrderEvent> {}
|
||||
class DocumentStateMachineConfiguration
|
||||
extends org.springframework.statemachine.config.StateMachineConfigurerAdapter<DocumentState, DocumentEvent> {}
|
||||
""");
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
CallChain orderChain = CallChain.builder()
|
||||
.triggerPoint(TriggerPoint.builder()
|
||||
.event("com.example.OrderEvent.PAY")
|
||||
.eventTypeFqn("com.example.OrderEvent")
|
||||
.stateTypeFqn("com.example.OrderState")
|
||||
.className("com.example.SharedDispatcher")
|
||||
.methodName("payOrder")
|
||||
.build())
|
||||
.methodChain(List.of("com.example.SharedDispatcher.payOrder()"))
|
||||
.build();
|
||||
CallChain documentChain = CallChain.builder()
|
||||
.triggerPoint(TriggerPoint.builder()
|
||||
.event("com.example.DocumentEvent.SUBMIT")
|
||||
.eventTypeFqn("com.example.DocumentEvent")
|
||||
.stateTypeFqn("com.example.DocumentState")
|
||||
.className("com.example.SharedDispatcher")
|
||||
.methodName("submitDocument")
|
||||
.build())
|
||||
.methodChain(List.of("com.example.SharedDispatcher.submitDocument()"))
|
||||
.build();
|
||||
|
||||
assertThat(engine.isRoutedToCorrectMachine(
|
||||
orderChain, "com.example.OrderStateMachineConfiguration", context)).isTrue();
|
||||
assertThat(engine.isRoutedToCorrectMachine(
|
||||
orderChain, "com.example.DocumentStateMachineConfiguration", context)).isFalse();
|
||||
assertThat(engine.isRoutedToCorrectMachine(
|
||||
documentChain, "com.example.DocumentStateMachineConfiguration", context)).isTrue();
|
||||
assertThat(engine.isRoutedToCorrectMachine(
|
||||
documentChain, "com.example.OrderStateMachineConfiguration", context)).isFalse();
|
||||
}
|
||||
|
||||
private static void writeTwoMachineSample(Path tempDir) throws Exception {
|
||||
Path orderPkg = tempDir.resolve("com/example/order");
|
||||
Path invoicePkg = tempDir.resolve("com/example/invoice");
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.resolver;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class BooleanConstraintEvaluatorBindingTest {
|
||||
|
||||
@Test
|
||||
void shouldEvaluateEqualsIgnoreCaseAgainstPathVariableBinding() {
|
||||
String constraint = "\"ORDER\".equalsIgnoreCase(machineType)";
|
||||
assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings(constraint, Map.of("machineType", "ORDER")))
|
||||
.isTrue();
|
||||
assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings(constraint, Map.of("machineType", "DOCUMENT")))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldEvaluateDocumentBranchAgainstBinding() {
|
||||
String constraint = "\"DOCUMENT\".equalsIgnoreCase(machineType)";
|
||||
assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings(constraint, Map.of("machineType", "DOCUMENT")))
|
||||
.isTrue();
|
||||
assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings(constraint, Map.of("machineType", "ORDER")))
|
||||
.isFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Enterprise dedicated REST endpoints must link to transitions when call-graph resolution
|
||||
* proves a concrete machine enum literal on the dispatcher branch.
|
||||
*/
|
||||
class EnterpriseDedicatedEndpointLinkingTest {
|
||||
|
||||
private static final String PAY_ENDPOINT = "POST /api/machine/order/pay";
|
||||
|
||||
@Test
|
||||
void astExportDedicatedPayEndpointShouldLinkToOrderPayTransition(@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 chain = findPayEndpointChain(json);
|
||||
|
||||
assertThat(chain.path("triggerPoint").path("event").asText())
|
||||
.isEqualTo("click.kamil.enterprise.machines.order.OrderEvent.PAY");
|
||||
assertThat(chain.path("matchedTransitions").isArray()).isTrue();
|
||||
assertThat(chain.path("matchedTransitions")).isNotEmpty();
|
||||
assertThat(chain.path("matchedTransitions").get(0).path("event").asText())
|
||||
.isEqualTo("click.kamil.enterprise.machines.order.OrderEvent.PAY");
|
||||
}
|
||||
|
||||
private static JsonNode findPayEndpointChain(JsonNode machineJson) {
|
||||
for (JsonNode chain : machineJson.path("metadata").path("callChains")) {
|
||||
if (PAY_ENDPOINT.equals(chain.path("entryPoint").path("name").asText())) {
|
||||
return chain;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("pay endpoint chain not found");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
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.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Per-branch dispatcher splitting: if-else machineType arms must resolve to branch-specific
|
||||
* valueOf triggers and constraints, not a collapsed ternary across machines.
|
||||
*/
|
||||
class EnterpriseDispatcherBranchSplitTest {
|
||||
|
||||
@Test
|
||||
void shouldResolveBranchSpecificValueOfForEachMachineTypeBinding(@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);
|
||||
} else if ("USER".equalsIgnoreCase(machineType)) {
|
||||
fireUser(eventString);
|
||||
}
|
||||
}
|
||||
void fireOrder(String eventString) {
|
||||
OrderEvent event = OrderEvent.valueOf(eventString.toUpperCase());
|
||||
send(event);
|
||||
}
|
||||
void fireDocument(String eventString) {
|
||||
DocumentEvent event = DocumentEvent.valueOf(eventString.toUpperCase());
|
||||
send(event);
|
||||
}
|
||||
void fireUser(String eventString) {
|
||||
UserEvent event = UserEvent.valueOf(eventString.toUpperCase());
|
||||
send(event);
|
||||
}
|
||||
void send(OrderEvent event) {}
|
||||
void send(DocumentEvent event) {}
|
||||
void send(UserEvent event) {}
|
||||
}
|
||||
enum OrderEvent { PAY }
|
||||
enum DocumentEvent { SUBMIT }
|
||||
enum UserEvent { VERIFY }
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("App.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
HeuristicCallGraphEngine engine = new HeuristicCallGraphEngine(context);
|
||||
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();
|
||||
|
||||
TriggerPoint orderTrigger = TriggerPoint.builder()
|
||||
.className("com.example.StateMachineDispatcher")
|
||||
.methodName("send")
|
||||
.event("event")
|
||||
.build();
|
||||
|
||||
List<CallChain> chains = engine.findChains(List.of(entryPoint), List.of(orderTrigger));
|
||||
|
||||
CallChain orderChain = chains.stream()
|
||||
.filter(c -> c.getEntryPoint().getName().contains("/ORDER/"))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
List<CallChain> documentChains = chains.stream()
|
||||
.filter(c -> c.getEntryPoint().getName().contains("/DOCUMENT/"))
|
||||
.toList();
|
||||
assertThat(documentChains).isNotEmpty();
|
||||
CallChain documentChain = documentChains.stream()
|
||||
.filter(c -> c.getMethodChain().contains("com.example.StateMachineDispatcher.fireDocument"))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
|
||||
assertThat(orderChain.getTriggerPoint().getEvent())
|
||||
.contains("OrderEvent.valueOf")
|
||||
.doesNotContain("DocumentEvent")
|
||||
.doesNotContain("UserEvent")
|
||||
.doesNotContain("true ?");
|
||||
assertThat(orderChain.getTriggerPoint().getConstraint())
|
||||
.contains("ORDER")
|
||||
.doesNotContain("DOCUMENT");
|
||||
|
||||
assertThat(documentChain.getMethodChain())
|
||||
.contains("com.example.StateMachineDispatcher.fireDocument")
|
||||
.doesNotContain("com.example.StateMachineDispatcher.fireOrder");
|
||||
assertThat(documentChain.getTriggerPoint().getEvent())
|
||||
.satisfiesAnyOf(
|
||||
e -> assertThat(e).contains("DocumentEvent.valueOf"),
|
||||
e -> assertThat(e).isEqualTo("event"));
|
||||
assertThat(documentChain.getTriggerPoint().getConstraint())
|
||||
.contains("DOCUMENT")
|
||||
.doesNotContain("USER");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindingExpanderShouldProduceMachineTypeVariants(@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)) {
|
||||
order(eventString);
|
||||
} else if ("DOCUMENT".equalsIgnoreCase(machineType)) {
|
||||
document(eventString);
|
||||
}
|
||||
}
|
||||
void order(String eventString) {}
|
||||
void document(String eventString) {}
|
||||
}
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("App.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
HeuristicCallGraphEngine engine = new HeuristicCallGraphEngine(context);
|
||||
EntryPoint entryPoint = EntryPoint.builder()
|
||||
.className("com.example.MachineController")
|
||||
.methodName("transition")
|
||||
.parameters(List.of(
|
||||
EntryPoint.Parameter.builder()
|
||||
.name("machineType")
|
||||
.type("String")
|
||||
.annotations(List.of("PathVariable"))
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
List<Map<String, String>> variants = EntryPointBindingExpander.expandPathVariableBindings(
|
||||
entryPoint, context, engine.buildCallGraph());
|
||||
|
||||
assertThat(variants).extracting(map -> map.get("machineType"))
|
||||
.containsExactlyInAnyOrder("ORDER", "DOCUMENT");
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,9 @@ class EnterpriseDispatcherMatchedTransitionsRegressionTest {
|
||||
|
||||
private static JsonNode findTransitionEndpointChain(JsonNode machineJson) {
|
||||
for (JsonNode chain : machineJson.path("metadata").path("callChains")) {
|
||||
if (TRANSITION_ENDPOINT.equals(chain.path("entryPoint").path("name").asText())) {
|
||||
String name = chain.path("entryPoint").path("name").asText();
|
||||
if (TRANSITION_ENDPOINT.equals(name)
|
||||
|| (name.contains("/transition/{event}") && name.contains("POST /api/machine/"))) {
|
||||
return chain;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,4 +143,59 @@ class EntryPointBindingExpanderTest {
|
||||
assertThat(chains.stream().filter(chain -> chain.getEntryPoint().getName().endsWith("order.pay")).findFirst().orElseThrow()
|
||||
.getMethodChain()).contains("com.example.CentralDispatcher.orderPay");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExpandPathVariableFromIfElseEqualsChain(@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) {}
|
||||
void fireDocument(String eventString) {}
|
||||
}
|
||||
""";
|
||||
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).extracting(map -> map.get("machineType"))
|
||||
.containsExactlyInAnyOrder("ORDER", "DOCUMENT");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
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.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Export must work on standard Spring State Machine patterns without hints.json.
|
||||
*/
|
||||
class ExportWithoutHintsTest {
|
||||
|
||||
@Test
|
||||
void shouldDetectSendEventTriggersWithoutHintsJson(@TempDir Path tempDir) throws Exception {
|
||||
String source = """
|
||||
package com.example;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
public class OrderService {
|
||||
public void pay(StateMachine<OrderState, OrderEvent> sm) {
|
||||
sm.sendEvent(OrderEvent.PAY);
|
||||
}
|
||||
}
|
||||
enum OrderState { NEW, PAID }
|
||||
enum OrderEvent { PAY }
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("OrderService.java"), source);
|
||||
assertThat(tempDir.resolve("hints.json")).doesNotExist();
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.scan(tempDir);
|
||||
assertThat(context.getLibraryHints()).isEmpty();
|
||||
|
||||
GenericEventDetector detector = new GenericEventDetector(
|
||||
context, context.getConstantResolver(), context.getLibraryHints());
|
||||
List<TriggerPoint> triggers = detector.detect(
|
||||
context.getCompilationUnits().iterator().next());
|
||||
|
||||
assertThat(triggers).isNotEmpty();
|
||||
assertThat(triggers)
|
||||
.extracting(TriggerPoint::getEvent)
|
||||
.anyMatch(e -> e != null && e.contains("PAY"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class ExternalTriggerPolicyTest {
|
||||
|
||||
@Test
|
||||
void pathVariableEventParameterShouldBeExternal() {
|
||||
EntryPoint entryPoint = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/{event}")
|
||||
.className("com.example.Api")
|
||||
.methodName("trigger")
|
||||
.parameters(List.of(EntryPoint.Parameter.builder()
|
||||
.name("event")
|
||||
.type("String")
|
||||
.annotations(List.of("PathVariable"))
|
||||
.build()))
|
||||
.build();
|
||||
TriggerPoint trigger = TriggerPoint.builder()
|
||||
.event("eventString.toUpperCase()")
|
||||
.build();
|
||||
|
||||
assertThat(ExternalTriggerPolicy.isExternalFromSource(
|
||||
entryPoint, trigger, "com.example.Api.trigger", "event", null)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void requestBodyEnumShouldBeInternal(@TempDir Path tempDir) throws Exception {
|
||||
String source = """
|
||||
package com.example;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
public class Api {
|
||||
@PostMapping("/pay")
|
||||
public void pay(@RequestBody OrderEvent event) {
|
||||
fire(event);
|
||||
}
|
||||
void fire(OrderEvent event) {}
|
||||
}
|
||||
enum OrderEvent { PAY }
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("Api.java"), source);
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.scan(tempDir);
|
||||
|
||||
EntryPoint entryPoint = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /pay")
|
||||
.className("com.example.Api")
|
||||
.methodName("pay")
|
||||
.build();
|
||||
TriggerPoint trigger = TriggerPoint.builder()
|
||||
.event("com.example.OrderEvent.PAY")
|
||||
.polymorphicEvents(List.of("com.example.OrderEvent.PAY"))
|
||||
.build();
|
||||
|
||||
assertThat(ExternalTriggerPolicy.isExternalFromSource(
|
||||
entryPoint, trigger, "com.example.Api.pay", "event", context)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void concreteEnumLiteralFromDedicatedEndpointShouldBeInternal() {
|
||||
EntryPoint entryPoint = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /api/order/pay")
|
||||
.className("com.example.Api")
|
||||
.methodName("pay")
|
||||
.build();
|
||||
TriggerPoint trigger = TriggerPoint.builder()
|
||||
.event("com.example.OrderEvent.PAY")
|
||||
.polymorphicEvents(List.of("com.example.OrderEvent.PAY"))
|
||||
.build();
|
||||
|
||||
assertThat(ExternalTriggerPolicy.isExternalFromSource(
|
||||
entryPoint, trigger, "com.example.Api.pay", null, null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void requestBodyRecordEnumComponentShouldBeInternal(@TempDir Path tempDir) throws Exception {
|
||||
String source = """
|
||||
package com.example;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
public class Api {
|
||||
@PostMapping("/pay")
|
||||
public void pay(@RequestBody OrderRequest request) {
|
||||
fire(request.event());
|
||||
}
|
||||
void fire(OrderEvent event) {}
|
||||
}
|
||||
record OrderRequest(OrderEvent event) {}
|
||||
enum OrderEvent { PAY }
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("Api.java"), source);
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
EntryPoint entryPoint = EntryPoint.builder()
|
||||
.type(EntryPoint.Type.REST)
|
||||
.name("POST /pay")
|
||||
.className("com.example.Api")
|
||||
.methodName("pay")
|
||||
.build();
|
||||
TriggerPoint trigger = TriggerPoint.builder()
|
||||
.event("com.example.OrderEvent.PAY")
|
||||
.polymorphicEvents(List.of("com.example.OrderEvent.PAY"))
|
||||
.build();
|
||||
|
||||
assertThat(ExternalTriggerPolicy.isExternalFromSource(
|
||||
entryPoint, trigger, "com.example.Api.pay", "event", context)).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -158,4 +158,66 @@ class GenericEventDetectorControlFlowTest {
|
||||
assertThat(triggers).hasSize(1);
|
||||
assertThat(triggers.get(0).getSourceState()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDetectSourceStateFromLiteralSendEventArgument(@TempDir Path tempDir) throws IOException {
|
||||
String source = """
|
||||
package com.example;
|
||||
public class OrderService {
|
||||
private StateMachine sm;
|
||||
public void pay() {
|
||||
sm.sendEvent(OrderEvent.PAY, OrderState.PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
class StateMachine {
|
||||
public void sendEvent(OrderEvent e, OrderState s) {}
|
||||
}
|
||||
|
||||
enum OrderState { PENDING }
|
||||
enum OrderEvent { PAY }
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("OrderService.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.scan(tempDir);
|
||||
|
||||
GenericEventDetector detector = new GenericEventDetector(context, new ConstantResolver(), Collections.emptyList());
|
||||
List<TriggerPoint> triggers = detector.detect(
|
||||
(org.eclipse.jdt.core.dom.CompilationUnit) context.getTypeDeclaration("com.example.OrderService").getRoot());
|
||||
|
||||
assertThat(triggers).hasSize(1);
|
||||
assertThat(triggers.get(0).getSourceState()).isEqualTo("PENDING");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotGuessSourceStateFromVariableSendEventArgument(@TempDir Path tempDir) throws IOException {
|
||||
String source = """
|
||||
package com.example;
|
||||
public class OrderService {
|
||||
private StateMachine sm;
|
||||
public void pay(OrderState current) {
|
||||
sm.sendEvent(OrderEvent.PAY, current);
|
||||
}
|
||||
}
|
||||
|
||||
class StateMachine {
|
||||
public void sendEvent(OrderEvent e, OrderState s) {}
|
||||
}
|
||||
|
||||
enum OrderState { PENDING }
|
||||
enum OrderEvent { PAY }
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("OrderService.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.scan(tempDir);
|
||||
|
||||
GenericEventDetector detector = new GenericEventDetector(context, new ConstantResolver(), Collections.emptyList());
|
||||
List<TriggerPoint> triggers = detector.detect(
|
||||
(org.eclipse.jdt.core.dom.CompilationUnit) context.getTypeDeclaration("com.example.OrderService").getRoot());
|
||||
|
||||
assertThat(triggers).hasSize(1);
|
||||
assertThat(triggers.get(0).getSourceState()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,6 +525,18 @@ class HeuristicCallGraphEngineTypeTest {
|
||||
EntryPoint entry = EntryPoint.builder()
|
||||
.className("click.kamil.enterprise.web.StateMachineController")
|
||||
.methodName("transition")
|
||||
.name("POST /api/machine/{machineType}/transition/{event}")
|
||||
.parameters(java.util.List.of(
|
||||
EntryPoint.Parameter.builder()
|
||||
.name("machineType")
|
||||
.type("String")
|
||||
.annotations(java.util.List.of("PathVariable"))
|
||||
.build(),
|
||||
EntryPoint.Parameter.builder()
|
||||
.name("event")
|
||||
.type("String")
|
||||
.annotations(java.util.List.of("PathVariable"))
|
||||
.build()))
|
||||
.build();
|
||||
TriggerPoint trigger = TriggerPoint.builder()
|
||||
.className("click.kamil.enterprise.web.StateMachineDispatcher")
|
||||
@@ -534,7 +546,15 @@ class HeuristicCallGraphEngineTypeTest {
|
||||
|
||||
List<CallChain> chains = builder.findChains(List.of(entry), List.of(trigger));
|
||||
assertThat(chains).isNotEmpty();
|
||||
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents())
|
||||
.containsExactlyInAnyOrder("<SYMBOLIC: OrderEvent.*>", "<SYMBOLIC: DocumentEvent.*>", "<SYMBOLIC: UserEvent.*>");
|
||||
java.util.Set<String> polymorphicEvents = new java.util.LinkedHashSet<>();
|
||||
for (CallChain chain : chains) {
|
||||
if (chain.getTriggerPoint().getPolymorphicEvents() != null) {
|
||||
polymorphicEvents.addAll(chain.getTriggerPoint().getPolymorphicEvents());
|
||||
}
|
||||
assertThat(chain.getTriggerPoint().getEvent())
|
||||
.doesNotContain("true ?");
|
||||
}
|
||||
assertThat(polymorphicEvents)
|
||||
.contains("<SYMBOLIC: OrderEvent.*>", "<SYMBOLIC: DocumentEvent.*>", "<SYMBOLIC: UserEvent.*>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,6 +304,18 @@ class JdtCallGraphEngineIntegrationTest {
|
||||
EntryPoint entry = EntryPoint.builder()
|
||||
.className("click.kamil.enterprise.web.StateMachineController")
|
||||
.methodName("transition")
|
||||
.name("POST /api/machine/{machineType}/transition/{event}")
|
||||
.parameters(java.util.List.of(
|
||||
EntryPoint.Parameter.builder()
|
||||
.name("machineType")
|
||||
.type("String")
|
||||
.annotations(java.util.List.of("PathVariable"))
|
||||
.build(),
|
||||
EntryPoint.Parameter.builder()
|
||||
.name("event")
|
||||
.type("String")
|
||||
.annotations(java.util.List.of("PathVariable"))
|
||||
.build()))
|
||||
.build();
|
||||
TriggerPoint trigger = TriggerPoint.builder()
|
||||
.className("click.kamil.enterprise.web.StateMachineDispatcher")
|
||||
@@ -313,7 +325,15 @@ class JdtCallGraphEngineIntegrationTest {
|
||||
|
||||
List<CallChain> chains = jdtEngine.findChains(List.of(entry), List.of(trigger));
|
||||
assertThat(chains).isNotEmpty();
|
||||
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents())
|
||||
.containsExactlyInAnyOrder("<SYMBOLIC: OrderEvent.*>", "<SYMBOLIC: DocumentEvent.*>", "<SYMBOLIC: UserEvent.*>");
|
||||
java.util.Set<String> polymorphicEvents = new java.util.LinkedHashSet<>();
|
||||
for (CallChain chain : chains) {
|
||||
if (chain.getTriggerPoint().getPolymorphicEvents() != null) {
|
||||
polymorphicEvents.addAll(chain.getTriggerPoint().getPolymorphicEvents());
|
||||
}
|
||||
assertThat(chain.getTriggerPoint().getEvent())
|
||||
.doesNotContain("true ?");
|
||||
}
|
||||
assertThat(polymorphicEvents)
|
||||
.contains("<SYMBOLIC: OrderEvent.*>", "<SYMBOLIC: DocumentEvent.*>", "<SYMBOLIC: UserEvent.*>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
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.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class VariableTracerBranchFilterTest {
|
||||
|
||||
@Test
|
||||
void shouldReturnBranchLocalInitializerWithoutCrossBranchTernary(@TempDir Path tempDir) throws Exception {
|
||||
String source = """
|
||||
package com.example;
|
||||
class StateMachineDispatcher {
|
||||
void fireDocument(String eventString) {
|
||||
DocumentEvent event = DocumentEvent.valueOf(eventString.toUpperCase());
|
||||
send(event);
|
||||
}
|
||||
void send(DocumentEvent event) {}
|
||||
}
|
||||
enum DocumentEvent { SUBMIT }
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("App.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.scan(tempDir);
|
||||
|
||||
HeuristicCallGraphEngine engine = new HeuristicCallGraphEngine(context);
|
||||
String traced = engine.variableTracer.traceLocalVariable(
|
||||
"com.example.StateMachineDispatcher.fireDocument",
|
||||
"event",
|
||||
Map.of("machineType", "DOCUMENT"));
|
||||
|
||||
assertThat(traced).contains("DocumentEvent.valueOf");
|
||||
}
|
||||
}
|
||||
@@ -322,6 +322,46 @@ class AnalysisCanonicalFormValidatorTest {
|
||||
.contains("metadata.callChains[0].matchedTransitions");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFailWhenDedicatedEndpointHasConcreteLiteralEventButNoMatchedTransitions() {
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
.name("com.example.config.OrderStateMachineConfiguration")
|
||||
.stateTypeFqn("com.example.order.OrderState")
|
||||
.eventTypeFqn("com.example.order.OrderEvent")
|
||||
.transitions(List.of(transition(
|
||||
"com.example.order.OrderEvent.PAY",
|
||||
"com.example.order.OrderState.NEW",
|
||||
"com.example.order.OrderState.PAID")))
|
||||
.metadata(CodebaseMetadata.builder()
|
||||
.callChains(List.of(CallChain.builder()
|
||||
.entryPoint(click.kamil.springstatemachineexporter.analysis.model.EntryPoint.builder()
|
||||
.type(click.kamil.springstatemachineexporter.analysis.model.EntryPoint.Type.REST)
|
||||
.name("POST /api/machine/order/pay")
|
||||
.className("com.example.web.StateMachineController")
|
||||
.methodName("payOrder")
|
||||
.build())
|
||||
.triggerPoint(TriggerPoint.builder()
|
||||
.event("com.example.order.OrderEvent.PAY")
|
||||
.className("com.example.web.StateMachineDispatcher")
|
||||
.methodName("payOrder")
|
||||
.sourceFile("StateMachineDispatcher.java")
|
||||
.eventTypeFqn("com.example.order.OrderEvent")
|
||||
.build())
|
||||
.build()))
|
||||
.build())
|
||||
.build();
|
||||
|
||||
List<AnalysisCanonicalFormValidator.Violation> violations =
|
||||
AnalysisCanonicalFormValidator.validateWithMachineTypes(
|
||||
result,
|
||||
new click.kamil.springstatemachineexporter.analysis.resolver.StateMachineTypeResolver.MachineTypes(
|
||||
"com.example.order.OrderState", "com.example.order.OrderEvent"));
|
||||
|
||||
assertThat(violations)
|
||||
.extracting(AnalysisCanonicalFormValidator.Violation::path)
|
||||
.contains("metadata.callChains[0].matchedTransitions");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAllowSymbolicPolymorphicEventsWithoutMatchedTransitions() {
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
|
||||
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 157 KiB |
@@ -123,6 +123,120 @@
|
||||
"ambiguous" : false
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/document/submit",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "submitDocument",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/document/submit",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/document/approve",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "approveDocument",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/document/approve",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/document/reject",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "rejectDocument",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/document/reject",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/ORDER/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/ORDER/transition/{event}",
|
||||
"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/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/DOCUMENT/transition/{event}",
|
||||
"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/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/USER/transition/{event}",
|
||||
"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/{machineType}/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
@@ -149,12 +263,126 @@
|
||||
"callChains" : [ {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/{machineType}/transition/{event}",
|
||||
"name" : "POST /api/machine/document/submit",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "submitDocument",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/document/submit",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
},
|
||||
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.submitDocument", "click.kamil.enterprise.web.StateMachineDispatcher.submitDocument" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "click.kamil.enterprise.machines.document.DocumentEvent.SUBMIT",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
|
||||
"methodName" : "submitDocument",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : "click.kamil.enterprise.machines.document.DocumentState.DRAFT",
|
||||
"lineNumber" : 44,
|
||||
"polymorphicEvents" : [ "click.kamil.enterprise.machines.document.DocumentEvent.SUBMIT" ],
|
||||
"external" : false,
|
||||
"constraint" : null,
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"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"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/document/approve",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "approveDocument",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/document/approve",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
},
|
||||
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.approveDocument", "click.kamil.enterprise.web.StateMachineDispatcher.approveDocument" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "click.kamil.enterprise.machines.document.DocumentEvent.APPROVE",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
|
||||
"methodName" : "approveDocument",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : "click.kamil.enterprise.machines.document.DocumentState.IN_REVIEW",
|
||||
"lineNumber" : 51,
|
||||
"polymorphicEvents" : [ "click.kamil.enterprise.machines.document.DocumentEvent.APPROVE" ],
|
||||
"external" : false,
|
||||
"constraint" : null,
|
||||
"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"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/document/reject",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "rejectDocument",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/document/reject",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
},
|
||||
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.rejectDocument", "click.kamil.enterprise.web.StateMachineDispatcher.rejectDocument" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "click.kamil.enterprise.machines.document.DocumentEvent.REJECT",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
|
||||
"methodName" : "rejectDocument",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : "click.kamil.enterprise.machines.document.DocumentState.IN_REVIEW",
|
||||
"lineNumber" : 58,
|
||||
"polymorphicEvents" : [ "click.kamil.enterprise.machines.document.DocumentEvent.REJECT" ],
|
||||
"external" : false,
|
||||
"constraint" : null,
|
||||
"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"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/ORDER/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/{machineType}/transition/{event}",
|
||||
"path" : "/api/machine/ORDER/transition/{event}",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
@@ -173,7 +401,7 @@
|
||||
},
|
||||
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "true ? OrderEvent.valueOf(eventString.toUpperCase()) : true ? DocumentEvent.valueOf(eventString.toUpperCase()) : UserEvent.valueOf(eventString.toUpperCase())",
|
||||
"event" : "OrderEvent.valueOf(eventString.toUpperCase())",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
|
||||
"methodName" : "dispatch",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
|
||||
@@ -183,8 +411,92 @@
|
||||
"lineNumber" : 87,
|
||||
"polymorphicEvents" : [ ],
|
||||
"external" : true,
|
||||
"constraint" : "!(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : true
|
||||
"constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/DOCUMENT/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/DOCUMENT/transition/{event}",
|
||||
"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" : 87,
|
||||
"polymorphicEvents" : [ ],
|
||||
"external" : true,
|
||||
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/USER/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/USER/transition/{event}",
|
||||
"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" : true,
|
||||
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
|
||||
@@ -152,18 +152,18 @@
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
"type" : "REST",
|
||||
"name" : "GET /api/base/{id}",
|
||||
"className" : "click.kamil.examples.statemachine.extended.web.PaymentController",
|
||||
"methodName" : "processBaseEndpoint",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/PaymentController.java",
|
||||
"name" : "POST /api/orders/resume",
|
||||
"className" : "click.kamil.examples.statemachine.extended.web.OrderController",
|
||||
"methodName" : "resumeOrder",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/base/{id}",
|
||||
"verb" : "GET"
|
||||
"path" : "/api/orders/resume",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "id",
|
||||
"name" : "orderId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
"annotations" : [ ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
@@ -180,8 +180,57 @@
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "GET /api/base/{id}",
|
||||
"className" : "click.kamil.examples.statemachine.extended.web.PaymentController",
|
||||
"methodName" : "processBaseEndpoint",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/PaymentController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/base/{id}",
|
||||
"verb" : "GET"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "id",
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
} ]
|
||||
} ],
|
||||
"callChains" : [ {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/orders/resume",
|
||||
"className" : "click.kamil.examples.statemachine.extended.web.OrderController",
|
||||
"methodName" : "resumeOrder",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/orders/resume",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "orderId",
|
||||
"type" : "String",
|
||||
"annotations" : [ ]
|
||||
} ]
|
||||
},
|
||||
"methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.resumeOrder", "click.kamil.examples.statemachine.extended.service.OrderService.resumeOrder" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "[LIFECYCLE:RESTORE]",
|
||||
"className" : "click.kamil.examples.statemachine.extended.service.OrderService",
|
||||
"methodName" : "resumeOrder",
|
||||
"sourceFile" : null,
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 29,
|
||||
"polymorphicEvents" : null,
|
||||
"external" : false,
|
||||
"constraint" : null,
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : "orderId",
|
||||
"matchedTransitions" : null
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/payment/{id}/capture",
|
||||
|
||||
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 23 KiB |
@@ -152,18 +152,18 @@
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
"type" : "REST",
|
||||
"name" : "GET /api/base/{id}",
|
||||
"className" : "click.kamil.examples.statemachine.extended.web.PaymentController",
|
||||
"methodName" : "processBaseEndpoint",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/PaymentController.java",
|
||||
"name" : "POST /api/orders/resume",
|
||||
"className" : "click.kamil.examples.statemachine.extended.web.OrderController",
|
||||
"methodName" : "resumeOrder",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/base/{id}",
|
||||
"verb" : "GET"
|
||||
"path" : "/api/orders/resume",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "id",
|
||||
"name" : "orderId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
"annotations" : [ ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
@@ -180,8 +180,57 @@
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "GET /api/base/{id}",
|
||||
"className" : "click.kamil.examples.statemachine.extended.web.PaymentController",
|
||||
"methodName" : "processBaseEndpoint",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/PaymentController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/base/{id}",
|
||||
"verb" : "GET"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "id",
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
} ]
|
||||
} ],
|
||||
"callChains" : [ {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/orders/resume",
|
||||
"className" : "click.kamil.examples.statemachine.extended.web.OrderController",
|
||||
"methodName" : "resumeOrder",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/extended/web/OrderController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/orders/resume",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "orderId",
|
||||
"type" : "String",
|
||||
"annotations" : [ ]
|
||||
} ]
|
||||
},
|
||||
"methodChain" : [ "click.kamil.examples.statemachine.extended.web.OrderController.resumeOrder", "click.kamil.examples.statemachine.extended.service.OrderService.resumeOrder" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "[LIFECYCLE:RESTORE]",
|
||||
"className" : "click.kamil.examples.statemachine.extended.service.OrderService",
|
||||
"methodName" : "resumeOrder",
|
||||
"sourceFile" : null,
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 29,
|
||||
"polymorphicEvents" : null,
|
||||
"external" : false,
|
||||
"constraint" : null,
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : "orderId",
|
||||
"matchedTransitions" : null
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/payment/{id}/capture",
|
||||
|
||||
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 223 KiB |
|
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 257 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 49 KiB |
@@ -75,6 +75,21 @@
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestBody" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "JMS",
|
||||
"name" : "JMS: order.queue",
|
||||
"className" : "click.kamil.maven.api.JmsOrderListener",
|
||||
"methodName" : "onMessage",
|
||||
"sourceFile" : "api-module/src/main/java/click/kamil/maven/api/JmsOrderListener.java",
|
||||
"metadata" : {
|
||||
"protocol" : "JMS",
|
||||
"destination" : "order.queue"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "message",
|
||||
"type" : "String",
|
||||
"annotations" : [ ]
|
||||
} ]
|
||||
} ],
|
||||
"callChains" : [ {
|
||||
"entryPoint" : {
|
||||
@@ -114,6 +129,44 @@
|
||||
"targetState" : "String.BUSY",
|
||||
"event" : "String.SUBMIT"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "JMS",
|
||||
"name" : "JMS: order.queue",
|
||||
"className" : "click.kamil.maven.api.JmsOrderListener",
|
||||
"methodName" : "onMessage",
|
||||
"sourceFile" : "api-module/src/main/java/click/kamil/maven/api/JmsOrderListener.java",
|
||||
"metadata" : {
|
||||
"protocol" : "JMS",
|
||||
"destination" : "order.queue"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "message",
|
||||
"type" : "String",
|
||||
"annotations" : [ ]
|
||||
} ]
|
||||
},
|
||||
"methodChain" : [ "click.kamil.maven.api.JmsOrderListener.onMessage", "click.kamil.maven.core.MavenOrderStateMachine.OrderService.onMessage" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "java.lang.String.ORDER_EVENT",
|
||||
"className" : "click.kamil.maven.core.MavenOrderStateMachine.OrderService",
|
||||
"methodName" : "onMessage",
|
||||
"sourceFile" : "core-module/src/main/java/click/kamil/maven/core/MavenOrderStateMachine.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : "java.lang.String.BUSY",
|
||||
"lineNumber" : 52,
|
||||
"polymorphicEvents" : [ "java.lang.String.ORDER_EVENT" ],
|
||||
"external" : false,
|
||||
"constraint" : null,
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "String.BUSY",
|
||||
"targetState" : "String.DONE",
|
||||
"event" : "String.ORDER_EVENT"
|
||||
} ]
|
||||
} ],
|
||||
"properties" : {
|
||||
"default" : { }
|
||||
|
||||
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 168 KiB |
@@ -100,6 +100,105 @@
|
||||
"ambiguous" : false
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/order/pay",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "payOrder",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/order/pay",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/order/ship",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "shipOrder",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/order/ship",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/ORDER/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/ORDER/transition/{event}",
|
||||
"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/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/DOCUMENT/transition/{event}",
|
||||
"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/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/USER/transition/{event}",
|
||||
"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/{machineType}/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
@@ -126,12 +225,88 @@
|
||||
"callChains" : [ {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/{machineType}/transition/{event}",
|
||||
"name" : "POST /api/machine/order/pay",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "payOrder",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/order/pay",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
},
|
||||
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.payOrder", "click.kamil.enterprise.web.StateMachineDispatcher.payOrder" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "click.kamil.enterprise.machines.order.OrderEvent.PAY",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
|
||||
"methodName" : "payOrder",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : "click.kamil.enterprise.machines.order.OrderState.NEW",
|
||||
"lineNumber" : 30,
|
||||
"polymorphicEvents" : [ "click.kamil.enterprise.machines.order.OrderEvent.PAY" ],
|
||||
"external" : false,
|
||||
"constraint" : null,
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : [ {
|
||||
"sourceState" : "click.kamil.enterprise.machines.order.OrderState.NEW",
|
||||
"targetState" : "click.kamil.enterprise.machines.order.OrderState.PENDING",
|
||||
"event" : "click.kamil.enterprise.machines.order.OrderEvent.PAY"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/order/ship",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "shipOrder",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/order/ship",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
},
|
||||
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.shipOrder", "click.kamil.enterprise.web.StateMachineDispatcher.shipOrder" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "click.kamil.enterprise.machines.order.OrderEvent.SHIP",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
|
||||
"methodName" : "shipOrder",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : "click.kamil.enterprise.machines.order.OrderState.PENDING",
|
||||
"lineNumber" : 37,
|
||||
"polymorphicEvents" : [ "click.kamil.enterprise.machines.order.OrderEvent.SHIP" ],
|
||||
"external" : false,
|
||||
"constraint" : null,
|
||||
"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"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/ORDER/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/{machineType}/transition/{event}",
|
||||
"path" : "/api/machine/ORDER/transition/{event}",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
@@ -150,7 +325,7 @@
|
||||
},
|
||||
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "true ? OrderEvent.valueOf(eventString.toUpperCase()) : true ? DocumentEvent.valueOf(eventString.toUpperCase()) : UserEvent.valueOf(eventString.toUpperCase())",
|
||||
"event" : "OrderEvent.valueOf(eventString.toUpperCase())",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
|
||||
"methodName" : "dispatch",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
|
||||
@@ -160,8 +335,92 @@
|
||||
"lineNumber" : 81,
|
||||
"polymorphicEvents" : [ ],
|
||||
"external" : true,
|
||||
"constraint" : "\"ORDER\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : true
|
||||
"constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && \"ORDER\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/DOCUMENT/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/DOCUMENT/transition/{event}",
|
||||
"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" : true,
|
||||
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"ORDER\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/USER/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/USER/transition/{event}",
|
||||
"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" : true,
|
||||
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && \"ORDER\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
|
||||
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 55 KiB |
@@ -119,6 +119,51 @@
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/commands/document.submit",
|
||||
"className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController",
|
||||
"methodName" : "execute",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/commands/document.submit",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "commandKey",
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/commands/document.approve",
|
||||
"className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController",
|
||||
"methodName" : "execute",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/commands/document.approve",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "commandKey",
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/commands/document.reject",
|
||||
"className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController",
|
||||
"methodName" : "execute",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/commands/document.reject",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "commandKey",
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/commands/{commandKey}",
|
||||
@@ -266,7 +311,7 @@
|
||||
"lineNumber" : 81,
|
||||
"polymorphicEvents" : [ "click.kamil.examples.statemachine.layered.document.DocumentTransitionEvent.SUBMIT" ],
|
||||
"external" : false,
|
||||
"constraint" : "command == DOCUMENT_SUBMIT",
|
||||
"constraint" : "\"document.submit\".equalsIgnoreCase(commandKey) && command == DOCUMENT_SUBMIT",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
@@ -304,7 +349,7 @@
|
||||
"lineNumber" : 81,
|
||||
"polymorphicEvents" : [ "click.kamil.examples.statemachine.layered.document.DocumentTransitionEvent.APPROVE" ],
|
||||
"external" : false,
|
||||
"constraint" : "command == DOCUMENT_APPROVE",
|
||||
"constraint" : "\"document.approve\".equalsIgnoreCase(commandKey) && command == DOCUMENT_APPROVE",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
@@ -342,7 +387,7 @@
|
||||
"lineNumber" : 81,
|
||||
"polymorphicEvents" : [ "click.kamil.examples.statemachine.layered.document.DocumentTransitionEvent.REJECT" ],
|
||||
"external" : false,
|
||||
"constraint" : "command == DOCUMENT_REJECT",
|
||||
"constraint" : "\"document.reject\".equalsIgnoreCase(commandKey) && command == DOCUMENT_REJECT",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
|
||||
@@ -163,6 +163,51 @@
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/commands/order.pay",
|
||||
"className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController",
|
||||
"methodName" : "execute",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/commands/order.pay",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "commandKey",
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/commands/order.ship",
|
||||
"className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController",
|
||||
"methodName" : "execute",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/commands/order.ship",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "commandKey",
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/commands/order.cancel",
|
||||
"className" : "click.kamil.examples.statemachine.layered.web.GenericCommandController",
|
||||
"methodName" : "execute",
|
||||
"sourceFile" : "src/main/java/click/kamil/examples/statemachine/layered/web/GenericCommandController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/commands/order.cancel",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "commandKey",
|
||||
"type" : "String",
|
||||
"annotations" : [ "PathVariable" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/commands/{commandKey}",
|
||||
@@ -446,7 +491,7 @@
|
||||
"lineNumber" : 75,
|
||||
"polymorphicEvents" : [ "click.kamil.examples.statemachine.layered.order.OrderTransitionEvent.PAY" ],
|
||||
"external" : false,
|
||||
"constraint" : "command == ORDER_PAY",
|
||||
"constraint" : "\"order.pay\".equalsIgnoreCase(commandKey) && command == ORDER_PAY",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
@@ -484,7 +529,7 @@
|
||||
"lineNumber" : 75,
|
||||
"polymorphicEvents" : [ "click.kamil.examples.statemachine.layered.order.OrderTransitionEvent.SHIP" ],
|
||||
"external" : false,
|
||||
"constraint" : "command == ORDER_SHIP",
|
||||
"constraint" : "\"order.ship\".equalsIgnoreCase(commandKey) && command == ORDER_SHIP",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
@@ -522,7 +567,7 @@
|
||||
"lineNumber" : 75,
|
||||
"polymorphicEvents" : [ "click.kamil.examples.statemachine.layered.order.OrderTransitionEvent.CANCEL" ],
|
||||
"external" : false,
|
||||
"constraint" : "command == ORDER_CANCEL",
|
||||
"constraint" : "\"order.cancel\".equalsIgnoreCase(commandKey) && command == ORDER_CANCEL",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
|
||||
@@ -446,7 +446,7 @@
|
||||
},
|
||||
"methodChain" : [ "click.kamil.web.JmsOrderListener.receiveCancelCommand", "click.kamil.service.StateMachineServiceImpl.sendMessageWithProvider" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "click.kamil.domain.OrderEvent.CANCEL",
|
||||
"event" : "eventProvider",
|
||||
"className" : "click.kamil.service.StateMachineServiceImpl",
|
||||
"methodName" : "sendMessageWithProvider",
|
||||
"sourceFile" : "service/src/main/java/click/kamil/service/StateMachineServiceImpl.java",
|
||||
@@ -454,10 +454,10 @@
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 50,
|
||||
"polymorphicEvents" : [ "click.kamil.domain.OrderEvent.CANCEL" ],
|
||||
"polymorphicEvents" : null,
|
||||
"external" : false,
|
||||
"constraint" : "event != null",
|
||||
"ambiguous" : true
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
|
||||
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 223 KiB |
|
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 211 KiB |
@@ -93,6 +93,105 @@
|
||||
"ambiguous" : false
|
||||
} ],
|
||||
"entryPoints" : [ {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/user/verify",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "verifyUser",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/user/verify",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/user/suspend",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "suspendUser",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/user/suspend",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
}, {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/ORDER/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/ORDER/transition/{event}",
|
||||
"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/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/DOCUMENT/transition/{event}",
|
||||
"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/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/USER/transition/{event}",
|
||||
"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/{machineType}/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
@@ -119,12 +218,84 @@
|
||||
"callChains" : [ {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/{machineType}/transition/{event}",
|
||||
"name" : "POST /api/machine/user/verify",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "verifyUser",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/user/verify",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
},
|
||||
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.verifyUser", "click.kamil.enterprise.web.StateMachineDispatcher.verifyUser" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "click.kamil.enterprise.machines.user.UserEvent.VERIFY",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
|
||||
"methodName" : "verifyUser",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : "click.kamil.enterprise.machines.user.UserState.REGISTERED",
|
||||
"lineNumber" : 65,
|
||||
"polymorphicEvents" : [ "click.kamil.enterprise.machines.user.UserEvent.VERIFY" ],
|
||||
"external" : false,
|
||||
"constraint" : null,
|
||||
"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"
|
||||
} ]
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/user/suspend",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "suspendUser",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/user/suspend",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
"name" : "userId",
|
||||
"type" : "String",
|
||||
"annotations" : [ "RequestParam" ]
|
||||
} ]
|
||||
},
|
||||
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.suspendUser", "click.kamil.enterprise.web.StateMachineDispatcher.suspendUser" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "click.kamil.enterprise.machines.user.UserEvent.SUSPEND",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
|
||||
"methodName" : "suspendUser",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
|
||||
"sourceModule" : null,
|
||||
"stateMachineId" : null,
|
||||
"sourceState" : null,
|
||||
"lineNumber" : 72,
|
||||
"polymorphicEvents" : [ ],
|
||||
"external" : false,
|
||||
"constraint" : null,
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/ORDER/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/{machineType}/transition/{event}",
|
||||
"path" : "/api/machine/ORDER/transition/{event}",
|
||||
"verb" : "POST"
|
||||
},
|
||||
"parameters" : [ {
|
||||
@@ -143,7 +314,7 @@
|
||||
},
|
||||
"methodChain" : [ "click.kamil.enterprise.web.StateMachineController.transition", "click.kamil.enterprise.web.StateMachineDispatcher.dispatch" ],
|
||||
"triggerPoint" : {
|
||||
"event" : "true ? OrderEvent.valueOf(eventString.toUpperCase()) : true ? DocumentEvent.valueOf(eventString.toUpperCase()) : UserEvent.valueOf(eventString.toUpperCase())",
|
||||
"event" : "OrderEvent.valueOf(eventString.toUpperCase())",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineDispatcher",
|
||||
"methodName" : "dispatch",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineDispatcher.java",
|
||||
@@ -153,8 +324,92 @@
|
||||
"lineNumber" : 93,
|
||||
"polymorphicEvents" : [ ],
|
||||
"external" : true,
|
||||
"constraint" : "!(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : true
|
||||
"constraint" : "\"ORDER\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/DOCUMENT/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/DOCUMENT/transition/{event}",
|
||||
"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" : true,
|
||||
"constraint" : "\"DOCUMENT\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
}, {
|
||||
"entryPoint" : {
|
||||
"type" : "REST",
|
||||
"name" : "POST /api/machine/USER/transition/{event}",
|
||||
"className" : "click.kamil.enterprise.web.StateMachineController",
|
||||
"methodName" : "transition",
|
||||
"sourceFile" : "src/main/java/click/kamil/enterprise/web/StateMachineController.java",
|
||||
"metadata" : {
|
||||
"path" : "/api/machine/USER/transition/{event}",
|
||||
"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" : 93,
|
||||
"polymorphicEvents" : [ ],
|
||||
"external" : true,
|
||||
"constraint" : "\"USER\".equalsIgnoreCase(machineType) && !(\"ORDER\".equalsIgnoreCase(machineType)) && !(\"DOCUMENT\".equalsIgnoreCase(machineType)) && \"USER\".equalsIgnoreCase(machineType)",
|
||||
"ambiguous" : false
|
||||
},
|
||||
"contextMachineId" : null,
|
||||
"matchedTransitions" : null
|
||||
|
||||