move files into modules
This commit is contained in:
45
state_machines/complex_state_machine/.gitignore
vendored
Normal file
45
state_machines/complex_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
|
||||
42
state_machines/complex_state_machine/build.gradle
Normal file
42
state_machines/complex_state_machine/build.gradle
Normal file
@@ -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,159 @@
|
||||
package click.kamil.examples.statemachine.complex;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
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.guard.Guard;
|
||||
|
||||
import java.util.EnumSet;
|
||||
@Configuration
|
||||
@EnableStateMachineFactory(name = "complexStateMachineFactory")
|
||||
public class ComplexStateMachineConfig extends StateMachineConfigurerAdapter<ComplexStateMachineConfig.States, ComplexStateMachineConfig.Events> {
|
||||
|
||||
public enum States {
|
||||
STATE1, STATE2, STATE3, STATE4, STATE5,
|
||||
STATE6, STATE7, STATE8, STATE9, STATE10,
|
||||
STATE11, STATE12, STATE13, STATE14, STATE15,
|
||||
STATE16, STATE17, STATE18, STATE19, STATE20
|
||||
}
|
||||
|
||||
public enum Events {
|
||||
EVENT1, EVENT2, EVENT3, EVENT4, EVENT5,
|
||||
EVENT6, EVENT7, EVENT8, EVENT9, EVENT10,
|
||||
EVENT11, EVENT12, EVENT13, EVENT14, EVENT15
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception {
|
||||
config
|
||||
.withConfiguration()
|
||||
.autoStartup(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(States.STATE1)
|
||||
.states(EnumSet.allOf(States.class))
|
||||
.stateEntry(States.STATE5, logEntryAction("Entered STATE5"))
|
||||
.stateExit(States.STATE10, logExitAction("Exited STATE10"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
|
||||
|
||||
// External transitions
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
private Guard<States, Events> guardVarEquals(String expected) {
|
||||
return context -> {
|
||||
Object var = context.getExtendedState().getVariables().get("var");
|
||||
return expected.equals(var);
|
||||
};
|
||||
}
|
||||
|
||||
private 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,11 @@
|
||||
package click.kamil.examples.statemachine.complex.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() {
|
||||
}
|
||||
|
||||
}
|
||||
45
state_machines/dynamic_state_machine/.gitignore
vendored
Normal file
45
state_machines/dynamic_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
|
||||
42
state_machines/dynamic_state_machine/build.gradle
Normal file
42
state_machines/dynamic_state_machine/build.gradle
Normal file
@@ -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,49 @@
|
||||
package click.kamil.examples.statemachine.dynamic;
|
||||
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.config.StateMachineBuilder;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class DynamicStateMachineExample {
|
||||
|
||||
public enum States {
|
||||
DRAFT, REVIEW, APPROVED
|
||||
}
|
||||
|
||||
public enum Events {
|
||||
SUBMIT, APPROVE
|
||||
}
|
||||
|
||||
public static StateMachine<States, Events> buildStateMachine() throws Exception {
|
||||
StateMachineBuilder.Builder<States, Events> builder = StateMachineBuilder.builder();
|
||||
|
||||
builder.configureStates()
|
||||
.withStates()
|
||||
.initial(States.DRAFT)
|
||||
.end(States.REVIEW)
|
||||
.states(EnumSet.allOf(States.class));
|
||||
|
||||
builder.configureTransitions()
|
||||
.withExternal()
|
||||
.source(States.DRAFT).target(States.REVIEW).event(Events.SUBMIT)
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(States.REVIEW).target(States.APPROVED).event(Events.APPROVE);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
StateMachine<States, Events> sm = buildStateMachine();
|
||||
|
||||
sm.start();
|
||||
System.out.println("Current State: " + sm.getState().getId());
|
||||
|
||||
sm.sendEvent(Events.SUBMIT);
|
||||
System.out.println("After SUBMIT: " + sm.getState().getId());
|
||||
|
||||
sm.sendEvent(Events.APPROVE);
|
||||
System.out.println("After APPROVE: " + sm.getState().getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package click.kamil.examples.statemachine.dynamic.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() {
|
||||
}
|
||||
|
||||
}
|
||||
45
state_machines/enumstate_state_machine/.gitignore
vendored
Normal file
45
state_machines/enumstate_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
|
||||
42
state_machines/enumstate_state_machine/build.gradle
Normal file
42
state_machines/enumstate_state_machine/build.gradle
Normal file
@@ -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,93 @@
|
||||
package click.kamil.examples.statemachine.enumstate;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
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.guard.Guard;
|
||||
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachineFactory(name = "kamilEnumStateMachineFactory")
|
||||
@Slf4j
|
||||
class KamilEnumStateMachineConfiguration extends StateMachineConfigurerAdapter<OrderStates, OrderEvents> {
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {
|
||||
Guard<OrderStates, OrderEvents> guard1 = null;
|
||||
Action<OrderStates, OrderEvents> action2 = null;
|
||||
transitions
|
||||
.withExternal().source(OrderStates.SUBMITTED).target(OrderStates.PAID).event(OrderEvents.PAY)
|
||||
.and()
|
||||
.withExternal().source(OrderStates.PAID).target(OrderStates.FULFILLED).event(OrderEvents.FULFILL)
|
||||
.and()
|
||||
.withExternal().source(OrderStates.SUBMITTED).target(OrderStates.CANCELED).event(OrderEvents.CANCEL).guard(new Guard<OrderStates, OrderEvents>() {
|
||||
@Override
|
||||
public boolean evaluate(StateContext<OrderStates, OrderEvents> context) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.and()
|
||||
.withExternal().source(OrderStates.PAID).target(OrderStates.CANCELED).event(OrderEvents.CANCEL)
|
||||
|
||||
.and()
|
||||
.withExternal().source(OrderStates.SUBMITTED).event(OrderEvents.ABCD)
|
||||
// it needs to have target specified to get added to .transitions collections
|
||||
.and()
|
||||
.withExternal().source(OrderStates.SUBMITTED).target(OrderStates.PAID1).event(OrderEvents.ABCD)
|
||||
//
|
||||
.and()
|
||||
.withChoice().source(OrderStates.PAID1)
|
||||
.first(OrderStates.PAID2, new Guard<OrderStates, OrderEvents>() {
|
||||
@Override
|
||||
public boolean evaluate(StateContext<OrderStates, OrderEvents> context) {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.then(OrderStates.PAID3, guard1)
|
||||
.then(OrderStates.HAPPEN, new Guard<OrderStates, OrderEvents>() {
|
||||
@Override
|
||||
public boolean evaluate(StateContext<OrderStates, OrderEvents> context) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.last(OrderStates.CANCELED)
|
||||
.and().withExternal().source(OrderStates.PAID2).target(OrderStates.CANCELED)
|
||||
.and().withExternal().source(OrderStates.PAID3).target(OrderStates.CANCELED)
|
||||
// .and().withLocal().source(OrderStates.SUBMITTED).target(OrderStates.CANCELED)
|
||||
.and().withExternal().source(OrderStates.PAID2).event(OrderEvents.ABCD).action(new Action<OrderStates, OrderEvents>() {
|
||||
@Override
|
||||
public void execute(StateContext<OrderStates, OrderEvents> context) {
|
||||
}
|
||||
}).action(action2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states) throws Exception {
|
||||
states.withStates()
|
||||
.initial(OrderStates.SUBMITTED)
|
||||
.state(OrderStates.PAID)
|
||||
.state(OrderStates.PAID2)
|
||||
.state(OrderStates.PAID3)
|
||||
.end(OrderStates.FULFILLED)
|
||||
.end(OrderStates.CANCELED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<OrderStates, OrderEvents> config) throws Exception {
|
||||
StateMachineListenerAdapter<OrderStates, OrderEvents> listenerAdapter = new StateMachineListenerAdapter<>() {
|
||||
@Override
|
||||
public void stateChanged(State<OrderStates, OrderEvents> from, State<OrderStates, OrderEvents> to) {
|
||||
log.info("state changed from {} to {}", from, to);
|
||||
}
|
||||
};
|
||||
config.withConfiguration()
|
||||
.autoStartup(false)
|
||||
.listener(listenerAdapter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package click.kamil.examples.statemachine.enumstate;
|
||||
|
||||
public enum OrderEvents {
|
||||
FULFILL, PAY, CANCEL,
|
||||
|
||||
ABCD, NOPE, IGNORE
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package click.kamil.examples.statemachine.enumstate;
|
||||
|
||||
public enum OrderStates {
|
||||
SUBMITTED, PAID, FULFILLED, CANCELED, PAID1, PAID2, PAID3, INVALID, HAPPEN, SKIPPED, NEVER
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package click.kamil.examples.statemachine.enumstate.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() {
|
||||
}
|
||||
|
||||
}
|
||||
45
state_machines/forkjoin_state_machine/.gitignore
vendored
Normal file
45
state_machines/forkjoin_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
|
||||
42
state_machines/forkjoin_state_machine/build.gradle
Normal file
42
state_machines/forkjoin_state_machine/build.gradle
Normal file
@@ -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,100 @@
|
||||
package click.kamil.examples.statemachine.forkjoin;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
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.guard.Guard;
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachineFactory(name = "forkJoinStateMachineFactory")
|
||||
public class ForkJoinStateMachineConfig extends StateMachineConfigurerAdapter<ForkJoinStateMachineConfig.States, ForkJoinStateMachineConfig.Events> {
|
||||
|
||||
public enum States {
|
||||
// Main flow
|
||||
START, FORK, JOIN, END,
|
||||
|
||||
// Region 1
|
||||
REGION1_STATE1, REGION1_STATE2,
|
||||
|
||||
// Region 2
|
||||
REGION2_STATE1, REGION2_STATE2
|
||||
}
|
||||
|
||||
public enum Events {
|
||||
TO_FORK, R1_NEXT, R2_NEXT, TO_JOIN, TO_END
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception {
|
||||
config
|
||||
.withConfiguration()
|
||||
.autoStartup(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(States.START)
|
||||
.state(States.FORK)
|
||||
.fork(States.FORK)
|
||||
.join(States.JOIN)
|
||||
.end(States.END)
|
||||
.and()
|
||||
.withStates()
|
||||
.parent(States.FORK)
|
||||
.region("Region1")
|
||||
.initial(States.REGION1_STATE1)
|
||||
.state(States.REGION1_STATE2)
|
||||
.and()
|
||||
.withStates()
|
||||
.parent(States.FORK)
|
||||
.region("Region2")
|
||||
.initial(States.REGION2_STATE1)
|
||||
.state(States.REGION2_STATE2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
|
||||
transitions
|
||||
// Initial path to fork
|
||||
.withExternal()
|
||||
.source(States.START).target(States.FORK).event(Events.TO_FORK)
|
||||
.and()
|
||||
// Fork: START → Region1 & Region2
|
||||
.withFork()
|
||||
.source(States.FORK)
|
||||
.target(States.REGION1_STATE1)
|
||||
.target(States.REGION2_STATE1)
|
||||
.and()
|
||||
// Region1 flow
|
||||
.withExternal()
|
||||
.source(States.REGION1_STATE1).target(States.REGION1_STATE2).event(Events.R1_NEXT)
|
||||
.and()
|
||||
// Region2 flow
|
||||
.withExternal()
|
||||
.source(States.REGION2_STATE1).target(States.REGION2_STATE2).event(Events.R2_NEXT)
|
||||
.and()
|
||||
// Join when both regions reach REGIONx_STATE2
|
||||
.withJoin()
|
||||
.source(States.REGION1_STATE2)
|
||||
.source(States.REGION2_STATE2)
|
||||
.target(States.JOIN)
|
||||
.and()
|
||||
// From join to end
|
||||
.withExternal()
|
||||
.source(States.JOIN).target(States.END).event(Events.TO_END);
|
||||
}
|
||||
|
||||
private Action<States, Events> log(String message) {
|
||||
return context -> System.out.println("ACTION: " + message);
|
||||
}
|
||||
|
||||
private Guard<States, Events> alwaysTrue() {
|
||||
return context -> true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package click.kamil.examples.statemachine.forkjoin.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() {
|
||||
}
|
||||
|
||||
}
|
||||
45
state_machines/inheritance_state_machine/.gitignore
vendored
Normal file
45
state_machines/inheritance_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
|
||||
42
state_machines/inheritance_state_machine/build.gradle
Normal file
42
state_machines/inheritance_state_machine/build.gradle
Normal file
@@ -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,172 @@
|
||||
package click.kamil.examples.statemachine.inheritancestate;
|
||||
|
||||
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 AbstractOneStateMachineConfiguration extends AbstractStateMachineConfiguration<States, Events> {
|
||||
|
||||
protected abstract void addAdditionalStates(StateConfigurer<States, Events> states);
|
||||
|
||||
protected abstract void addAdditionalTransitions(ExternalTransitionConfigurer<States, Events> transitions) throws Exception;
|
||||
|
||||
@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);
|
||||
|
||||
// EXTRA CHOICE
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private Guard<States, Events> guardVarEquals(String expected) {
|
||||
return context -> {
|
||||
Object var = context.getExtendedState().getVariables().get("var");
|
||||
return expected.equals(var);
|
||||
};
|
||||
}
|
||||
|
||||
private 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,6 @@
|
||||
package click.kamil.examples.statemachine.inheritancestate;
|
||||
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
|
||||
class AbstractStateMachineConfiguration<S,E> extends StateMachineConfigurerAdapter<S,E> {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package click.kamil.examples.statemachine.inheritancestate;
|
||||
|
||||
public enum Events {
|
||||
EVENT1, EVENT2, EVENT3, EVENT4, EVENT5,
|
||||
EVENT6, EVENT7, EVENT8, EVENT9, EVENT10,
|
||||
EVENT11, EVENT12, EVENT13, EVENT14, EVENT15,
|
||||
EVENTX, EVENTY, EVENTZ
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package click.kamil.examples.statemachine.inheritancestate;
|
||||
|
||||
import org.springframework.statemachine.config.configurers.ExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.StateConfigurer;
|
||||
|
||||
class OneStateMachineConfiguration extends AbstractOneStateMachineConfiguration {
|
||||
@Override
|
||||
protected void addAdditionalStates(StateConfigurer<States, Events> states) {
|
||||
states.state(States.STATE_EXTRA_1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addAdditionalTransitions(ExternalTransitionConfigurer<States, Events> transitions) throws Exception {
|
||||
transitions
|
||||
.and()
|
||||
.withExternal().event(Events.EVENTX)
|
||||
.source(States.STATE5)
|
||||
.target(States.STATE_EXTRA_1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package click.kamil.examples.statemachine.inheritancestate;
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package click.kamil.examples.statemachine.inheritancestate.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() {
|
||||
}
|
||||
|
||||
}
|
||||
45
state_machines/simple_state_machine/.gitignore
vendored
Normal file
45
state_machines/simple_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
|
||||
42
state_machines/simple_state_machine/build.gradle
Normal file
42
state_machines/simple_state_machine/build.gradle
Normal file
@@ -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,7 @@
|
||||
package click.kamil.examples.statemachine.simple;
|
||||
|
||||
public enum OrderEvents {
|
||||
FULFILL, PAY, CANCEL,
|
||||
|
||||
ABCD, NOPE, IGNORE
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package click.kamil.examples.statemachine.simple;
|
||||
|
||||
public enum OrderStates {
|
||||
SUBMITTED, PAID, FULFILLED, CANCELED, PAID1, PAID2, PAID3, INVALID, HAPPEN, SKIPPED, NEVER
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package click.kamil.examples.statemachine.simple;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
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.guard.Guard;
|
||||
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachineFactory(name = "simpleEnumStateMachineFactory")
|
||||
@Slf4j
|
||||
class SimpleEnumStateMachineConfiguration extends StateMachineConfigurerAdapter<OrderStates, OrderEvents> {
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {
|
||||
Guard<OrderStates, OrderEvents> guard1 = null;
|
||||
Action<OrderStates, OrderEvents> action2 = null;
|
||||
transitions
|
||||
.withExternal().source(OrderStates.SUBMITTED).target(OrderStates.PAID).event(OrderEvents.PAY)
|
||||
.and()
|
||||
.withExternal().source(OrderStates.PAID).target(OrderStates.FULFILLED).event(OrderEvents.FULFILL)
|
||||
.and()
|
||||
.withExternal().source(OrderStates.SUBMITTED).target(OrderStates.CANCELED).event(OrderEvents.CANCEL).guard(new Guard<OrderStates, OrderEvents>() {
|
||||
@Override
|
||||
public boolean evaluate(StateContext<OrderStates, OrderEvents> context) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.and()
|
||||
.withExternal().source(OrderStates.PAID).target(OrderStates.CANCELED).event(OrderEvents.CANCEL)
|
||||
|
||||
.and()
|
||||
.withExternal().source(OrderStates.SUBMITTED).event(OrderEvents.ABCD)
|
||||
// it needs to have target specified to get added to .transitions collections
|
||||
// .withExternal().source(OrderStates.SUBMITTED).target(OrderStates.SUBMITTED).event(OrderEvents.ABCD)
|
||||
//
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(OrderStates.SUBMITTED)
|
||||
.first(OrderStates.PAID2, new Guard<OrderStates, OrderEvents>() {
|
||||
@Override
|
||||
public boolean evaluate(StateContext<OrderStates, OrderEvents> context) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.last(OrderStates.PAID3)
|
||||
.and()
|
||||
.withChoice().source(OrderStates.PAID)
|
||||
.first(OrderStates.PAID1, new Guard<OrderStates, OrderEvents>() {
|
||||
@Override
|
||||
public boolean evaluate(StateContext<OrderStates, OrderEvents> context) {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.then(OrderStates.PAID2, guard1)
|
||||
.then(OrderStates.HAPPEN, new Guard<OrderStates, OrderEvents>() {
|
||||
@Override
|
||||
public boolean evaluate(StateContext<OrderStates, OrderEvents> context) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.last(OrderStates.PAID3)
|
||||
.and().withExternal().source(OrderStates.PAID2).target(OrderStates.CANCELED)
|
||||
.and().withExternal().source(OrderStates.PAID3).target(OrderStates.CANCELED)
|
||||
// .and().withLocal().source(OrderStates.SUBMITTED).target(OrderStates.CANCELED)
|
||||
.and().withExternal().source(OrderStates.PAID1).event(OrderEvents.ABCD).action(new Action<OrderStates, OrderEvents>() {
|
||||
@Override
|
||||
public void execute(StateContext<OrderStates, OrderEvents> context) {
|
||||
;
|
||||
}
|
||||
}).action(action2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states) throws Exception {
|
||||
states.withStates()
|
||||
.initial(OrderStates.SUBMITTED)
|
||||
.state(OrderStates.PAID)
|
||||
.state(OrderStates.PAID2)
|
||||
.state(OrderStates.PAID3)
|
||||
.end(OrderStates.FULFILLED)
|
||||
.end(OrderStates.CANCELED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<OrderStates, OrderEvents> config) throws Exception {
|
||||
StateMachineListenerAdapter<OrderStates, OrderEvents> listenerAdapter = new StateMachineListenerAdapter<>() {
|
||||
@Override
|
||||
public void stateChanged(State<OrderStates, OrderEvents> from, State<OrderStates, OrderEvents> to) {
|
||||
log.info("state changed from {} to {}", from, to);
|
||||
}
|
||||
};
|
||||
config.withConfiguration()
|
||||
.autoStartup(false)
|
||||
.listener(listenerAdapter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package click.kamil.examples.statemachine.simple.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