one more example
This commit is contained in:
@@ -9,4 +9,5 @@ include ':state_machines:enumstate_state_machine'
|
||||
include ':state_machines:forkjoin_state_machine'
|
||||
include ':state_machines:inheritance_state_machine'
|
||||
include ':state_machines:inheritance_extra_functions_state_machine'
|
||||
include ':state_machines:inheritance_extra_functions2_state_machine'
|
||||
include ':state_machines:simple_state_machine'
|
||||
|
||||
@@ -45,11 +45,8 @@ public class Main {
|
||||
new Scxml()
|
||||
);
|
||||
|
||||
List<TypeDeclaration> entryPoints = context.findEntryPointClasses(TARGET_ANNOTATIONS);
|
||||
for (TypeDeclaration td : entryPoints) {
|
||||
processEntryPoint(td, outputs, outputDir, context);
|
||||
}
|
||||
|
||||
exportAll(context, outputs, outputDir);
|
||||
|
||||
// Still handle methods returning StateMachine for now (might be harder to refactor to CodebaseContext)
|
||||
AstFileFinder finder = new AstFileFinder();
|
||||
List<Path> javaFiles = FileUtils.findFilesWithExtension(Set.of(inputDir), EXTENSION);
|
||||
@@ -61,6 +58,13 @@ public class Main {
|
||||
}
|
||||
}
|
||||
|
||||
public static void exportAll(CodebaseContext context, List<StateMachineExporter> outputs, Path outputDir) throws IOException {
|
||||
List<TypeDeclaration> entryPoints = context.findEntryPointClasses(TARGET_ANNOTATIONS);
|
||||
for (TypeDeclaration td : entryPoints) {
|
||||
processEntryPoint(td, outputs, outputDir, context);
|
||||
}
|
||||
}
|
||||
|
||||
static void processEntryPoint(TypeDeclaration td, List<StateMachineExporter> outputs, Path outputDir, CodebaseContext context) throws IOException {
|
||||
String className = td.getName().getFullyQualifiedName();
|
||||
System.out.println("Processing state machine config: " + className);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package click.kamil.springstatemachineexporter;
|
||||
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
import click.kamil.springstatemachineexporter.ast.out.Dot;
|
||||
import click.kamil.springstatemachineexporter.ast.out.PlantUml;
|
||||
import click.kamil.springstatemachineexporter.ast.out.Scxml;
|
||||
@@ -15,9 +16,9 @@ import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class RegressionTest {
|
||||
public class RegressionTest {
|
||||
|
||||
static List<TestScenario> provideTestScenarios() {
|
||||
private static List<TestScenario> provideTestScenarios() {
|
||||
return List.of(
|
||||
new TestScenario(
|
||||
"Complex State Machine",
|
||||
@@ -54,23 +55,28 @@ class RegressionTest {
|
||||
Path.of("../state_machines/inheritance_extra_functions_state_machine"),
|
||||
Path.of("src/test/resources/golden/TwoStateMachineExtraFunctionsConfiguration"),
|
||||
"TwoStateMachineConfiguration"
|
||||
),
|
||||
new TestScenario(
|
||||
"Three State Machine (Extra Functions 2)",
|
||||
Path.of("../state_machines/inheritance_extra_functions2_state_machine"),
|
||||
Path.of("src/test/resources/golden/ThreeStateMachineConfiguration"),
|
||||
"ThreeStateMachineConfiguration"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}")
|
||||
@MethodSource("provideTestScenarios")
|
||||
void testOutputMatchesGolden(TestScenario scenario, @TempDir Path tempDir) throws Exception {
|
||||
Main.runExporter(scenario.inputPath(), tempDir);
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.scan(scenario.inputPath());
|
||||
|
||||
List<StateMachineExporter> exporters = List.of(
|
||||
new PlantUml(),
|
||||
new Dot(),
|
||||
new Scxml()
|
||||
);
|
||||
List<StateMachineExporter> outputs = List.of(new PlantUml(), new Dot(), new Scxml());
|
||||
|
||||
Main.exportAll(context, outputs, tempDir);
|
||||
|
||||
String baseName = scenario.baseName();
|
||||
|
||||
for (StateMachineExporter exporter : exporters) {
|
||||
for (StateMachineExporter exporter : outputs) {
|
||||
String fileName = baseName + exporter.getFileExtension();
|
||||
|
||||
Path actualFile = tempDir.resolve(baseName).resolve(fileName);
|
||||
|
||||
45
state_machines/inheritance_extra_functions2_state_machine/.gitignore
vendored
Normal file
45
state_machines/inheritance_extra_functions2_state_machine/.gitignore
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
HELP.md
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
|
||||
|
||||
#### added
|
||||
*.png
|
||||
*.dot
|
||||
*.scxml.xml
|
||||
Combined.java
|
||||
@@ -0,0 +1,42 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.5.3'
|
||||
id 'io.spring.dependency-management' version '1.1.7'
|
||||
}
|
||||
|
||||
group = 'click.kamil'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
configurations {
|
||||
compileOnly {
|
||||
extendsFrom annotationProcessor
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter'
|
||||
implementation 'org.springframework.statemachine:spring-statemachine-starter:3.2.0'
|
||||
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package click.kamil.examples.statemachine.inheritanceextrafunctionsstate2;
|
||||
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ExternalTransitionConfigurer;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class AbstractStateMachineConfiguration<S,E> extends StateMachineConfigurerAdapter<S,E> {
|
||||
protected void addTransitionForMultipleEvents(
|
||||
StateMachineTransitionConfigurer<S, E> transitions,
|
||||
S source,
|
||||
S target,
|
||||
Consumer<ExternalTransitionConfigurer<S,E>> transitionCustomizer,
|
||||
E... events) {
|
||||
Stream.of(events).forEach(event -> {
|
||||
try {
|
||||
ExternalTransitionConfigurer<S, E> transitionConfigurer =
|
||||
transitions.withExternal().event(event).source(source).target(target);
|
||||
transitionCustomizer.accept(transitionConfigurer);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package click.kamil.examples.statemachine.inheritanceextrafunctionsstate2;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.StateConfigurer;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
|
||||
abstract class AbstractThreeStateMachineConfiguration extends AbstractStateMachineConfiguration<States, Events> {
|
||||
|
||||
protected abstract void addAdditionalStates(StateConfigurer<States, Events> states);
|
||||
|
||||
protected abstract void addAdditionalCancellationTransitions(StateMachineTransitionConfigurer<States, Events> transitions);
|
||||
|
||||
protected abstract void addAdditionalTransitions(ExternalTransitionConfigurer<States, Events> transitions) throws Exception;
|
||||
|
||||
protected void addAllCancellationTransitionsForSource(StateMachineTransitionConfigurer<States, Events> transitions, States source) {
|
||||
addCancellationTransitionForCancelEvents(transitions, source, Events.EVENT_CANCEL_2);
|
||||
}
|
||||
|
||||
private void addCancellationTransitionForCancelEvents(
|
||||
StateMachineTransitionConfigurer<States, Events> transitions,
|
||||
States source,
|
||||
Events... cancelEvents) {
|
||||
addTransitionForMultipleEvents(
|
||||
transitions,
|
||||
source,
|
||||
States.CANCEL,
|
||||
transitionConfigurer -> transitionConfigurer.action((context) -> System.out.println(context.getEvent().toString() + " " + context.getTransition().toString())),
|
||||
cancelEvents
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception {
|
||||
config
|
||||
.withConfiguration()
|
||||
.autoStartup(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
|
||||
StateConfigurer<States, Events> end = states
|
||||
.withStates()
|
||||
.initial(States.STATE1)
|
||||
.state(States.STATE2)
|
||||
.state(States.STATE3)
|
||||
.state(States.STATE4)
|
||||
.state(States.STATE5)
|
||||
.state(States.STATE6)
|
||||
.state(States.STATE7)
|
||||
.state(States.STATE8)
|
||||
.state(States.STATE9)
|
||||
.state(States.STATE10)
|
||||
.state(States.STATE11)
|
||||
.state(States.STATE12)
|
||||
.state(States.STATE13)
|
||||
.state(States.STATE14)
|
||||
.state(States.STATE15)
|
||||
.state(States.STATE16)
|
||||
.state(States.STATE17)
|
||||
.state(States.STATE18)
|
||||
.state(States.STATE19)
|
||||
.state(States.STATE20)
|
||||
.state(States.STATEX)
|
||||
.choice(States.STATEY)
|
||||
.end(States.STATEZ);
|
||||
addAdditionalStates(end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
|
||||
|
||||
// External transitions
|
||||
ExternalTransitionConfigurer<States, Events> t1 = transitions
|
||||
.withExternal().source(States.STATE1).target(States.STATE2).event(Events.EVENT1)
|
||||
.and()
|
||||
.withExternal().source(States.STATE2).target(States.STATE3).event(Events.EVENT2)
|
||||
.and()
|
||||
.withExternal().source(States.STATE3).target(States.STATE4).event(Events.EVENT3)
|
||||
.and()
|
||||
.withExternal().source(States.STATE4).target(States.STATE5).event(Events.EVENT4)
|
||||
.and()
|
||||
.withExternal().source(States.STATE5).target(States.STATE6).event(Events.EVENT5)
|
||||
.and()
|
||||
.withExternal().source(States.STATE6).target(States.STATE7).event(Events.EVENT6)
|
||||
.and()
|
||||
.withExternal().source(States.STATE7).target(States.STATE8).event(Events.EVENT7)
|
||||
.and()
|
||||
.withExternal().source(States.STATE8).target(States.STATE9).event(Events.EVENT8)
|
||||
.and()
|
||||
.withExternal().source(States.STATE9).target(States.STATE10).event(Events.EVENT9)
|
||||
.and()
|
||||
.withExternal().source(States.STATE10).target(States.STATE11).event(Events.EVENT10)
|
||||
.and()
|
||||
.withExternal().source(States.STATE11).target(States.STATE12).event(Events.EVENT11)
|
||||
.and()
|
||||
.withExternal().source(States.STATE12).target(States.STATE13).event(Events.EVENT12)
|
||||
.and()
|
||||
.withExternal().source(States.STATE13).target(States.STATE14).event(Events.EVENT13)
|
||||
.and()
|
||||
.withExternal().source(States.STATE14).target(States.STATE15).event(Events.EVENT14)
|
||||
.and()
|
||||
.withExternal().source(States.STATE15).target(States.STATE16).event(Events.EVENT15);
|
||||
|
||||
transitions.withExternal().source(States.STATE1).target(States.CANCEL).event(Events.EVENT_CANCEL)
|
||||
.and()
|
||||
.withExternal().source(States.STATE2).target(States.CANCEL).event(Events.EVENT_CANCEL)
|
||||
.and()
|
||||
.withExternal().source(States.STATE3).target(States.CANCEL).event(Events.EVENT_CANCEL)
|
||||
.and()
|
||||
.withExternal().source(States.STATE4).target(States.CANCEL).event(Events.EVENT_CANCEL)
|
||||
.and()
|
||||
.withExternal().source(States.STATE5).target(States.CANCEL).event(Events.EVENT_CANCEL);
|
||||
|
||||
// EXTRA CHOICE
|
||||
transitions.withExternal().source(States.STATE4).target(States.STATEY).event(Events.EVENTY);
|
||||
transitions.withChoice().source(States.STATEY).first(States.STATEX, guardVarEquals("value1")).last(States.STATEZ);
|
||||
|
||||
// Choice transitions (at least 10)
|
||||
transitions
|
||||
.withChoice()
|
||||
.source(States.STATE16)
|
||||
.first(States.STATE17, guardVarEquals("value1"))
|
||||
.then(States.STATE18, guardVarEquals("value2"))
|
||||
.last(States.STATE19)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.STATE17)
|
||||
.first(States.STATE20, guardEventHeaderEquals("header1", "foo"))
|
||||
.last(States.STATE16)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.STATE18)
|
||||
.first(States.STATE19, guardVarEquals("value3"))
|
||||
.last(States.STATE20)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.STATE19)
|
||||
.first(States.STATE1, guardVarEquals("reset"))
|
||||
.last(States.STATE20)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.STATE20)
|
||||
.first(States.STATE5, guardEventHeaderEquals("header2", "bar"))
|
||||
.last(States.STATE1)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.STATE11)
|
||||
.first(States.STATE13, guardVarEquals("goTo13"))
|
||||
.then(States.STATE14, guardVarEquals("goTo14"))
|
||||
.last(States.STATE15)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.STATE12)
|
||||
.first(States.STATE10, guardVarEquals("goBack10"))
|
||||
.last(States.STATE11)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.STATE14)
|
||||
.first(States.STATE12, guardVarEquals("loop12"))
|
||||
.last(States.STATE16)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.STATE9)
|
||||
.first(States.STATE8, guardVarEquals("stepBack"))
|
||||
.then(States.STATE7, guardVarEquals("stepBackMore"))
|
||||
.last(States.STATE6)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.STATE8)
|
||||
.first(States.STATE9, guardVarEquals("forward9"))
|
||||
.last(States.STATE10);
|
||||
|
||||
addAdditionalTransitions(t1);
|
||||
|
||||
addAdditionalCancellationTransitions(transitions);
|
||||
}
|
||||
|
||||
protected Guard<States, Events> guardVarEquals(String expected) {
|
||||
return context -> {
|
||||
Object var = context.getExtendedState().getVariables().get("var");
|
||||
return expected.equals(var);
|
||||
};
|
||||
}
|
||||
|
||||
protected Guard<States, Events> guardEventHeaderEquals(String headerName, String expected) {
|
||||
return context -> {
|
||||
Object header = context.getMessageHeader(headerName);
|
||||
return expected.equals(header);
|
||||
};
|
||||
}
|
||||
|
||||
private Action<States, Events> logEntryAction(String msg) {
|
||||
return context -> System.out.println(msg);
|
||||
}
|
||||
|
||||
private Action<States, Events> logExitAction(String msg) {
|
||||
return context -> System.out.println(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package click.kamil.examples.statemachine.inheritanceextrafunctionsstate2;
|
||||
|
||||
public enum Events {
|
||||
EVENT1, EVENT2, EVENT3, EVENT4, EVENT5,
|
||||
EVENT6, EVENT7, EVENT8, EVENT9, EVENT10,
|
||||
EVENT11, EVENT12, EVENT13, EVENT14, EVENT15,
|
||||
EVENTX, EVENTY, EVENTZ, EVENT_CANCEL, EVENT_CANCEL_2
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package click.kamil.examples.statemachine.inheritanceextrafunctionsstate2;
|
||||
|
||||
public enum States {
|
||||
STATE1, STATE2, STATE3, STATE4, STATE5,
|
||||
STATE6, STATE7, STATE8, STATE9, STATE10,
|
||||
STATE11, STATE12, STATE13, STATE14, STATE15,
|
||||
STATE16, STATE17, STATE18, STATE19, STATE20,
|
||||
STATEX, STATEY, STATEZ, STATE_EXTRA_1, STATE_EXTRA_2, STATE_EXTRA_3, CANCEL
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package click.kamil.examples.statemachine.inheritanceextrafunctionsstate2;
|
||||
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.StateConfigurer;
|
||||
|
||||
class ThreeStateMachineConfiguration extends AbstractThreeStateMachineConfiguration {
|
||||
@Override
|
||||
protected void addAdditionalStates(StateConfigurer<States, Events> states) {
|
||||
states.state(States.STATE_EXTRA_1);
|
||||
states.state(States.STATE_EXTRA_2);
|
||||
states.state(States.STATE_EXTRA_3);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addAdditionalCancellationTransitions(StateMachineTransitionConfigurer<States, Events> transitions) {
|
||||
addAllCancellationTransitionsForSource(transitions, States.STATE_EXTRA_1);
|
||||
addAllCancellationTransitionsForSource(transitions, States.STATE_EXTRA_2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addAdditionalTransitions(ExternalTransitionConfigurer<States, Events> transitions) throws Exception {
|
||||
transitions
|
||||
.and()
|
||||
.withExternal().event(Events.EVENTX)
|
||||
.source(States.STATE2)
|
||||
.target(States.STATE_EXTRA_1)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.STATE2)
|
||||
.first(States.STATE1, guardEventHeaderEquals("header1", "foo"))
|
||||
.last(States.STATE_EXTRA_1)
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(States.STATE_EXTRA_1)
|
||||
.event(Events.EVENTY)
|
||||
.target(States.STATE_EXTRA_3);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package click.kamil.examples.statemachine.inheritanceextrafunctionsstate2.app;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
class StateMachineApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StateMachineApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
spring.application.name=statemachinedemo
|
||||
@@ -0,0 +1,11 @@
|
||||
package click.kamil.examples.statemachine;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class MyTest {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user