Spring State Machine (#1493)
* Neo4j cleanup * Neo4j cleanup * Neo4j cleanup x2 * State Machine Init * cleanup * White background, Java Util Logging * Change to Logging * Static import of asserts. rename test methods * fix attempt for S3 -> S4 * Remove awaitility. add teardown * fix attempt for S3 -> S4 * fix attempt for S3 -> S4 Final
This commit is contained in:
committed by
Zeger Hendrikse
parent
365d75a8d7
commit
1c1c557a39
+5
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.spring.stateMachine.applicationReview;
|
||||
|
||||
public enum ApplicationReviewEvents {
|
||||
APPROVE, REJECT
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.spring.stateMachine.applicationReview;
|
||||
|
||||
public enum ApplicationReviewStates {
|
||||
PEER_REVIEW, PRINCIPAL_REVIEW, APPROVED, REJECTED
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package com.baeldung.spring.stateMachine.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
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
|
||||
@EnableStateMachine
|
||||
public class ForkJoinStateMachineConfiguration extends StateMachineConfigurerAdapter<String, String> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<String, String> config)
|
||||
throws Exception {
|
||||
config
|
||||
.withConfiguration()
|
||||
.autoStartup(true)
|
||||
.listener(new StateMachineListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial("SI")
|
||||
.fork("SFork")
|
||||
.join("SJoin")
|
||||
.end("SF")
|
||||
.and()
|
||||
.withStates()
|
||||
.parent("SFork")
|
||||
.initial("Sub1-1")
|
||||
.end("Sub1-2")
|
||||
.and()
|
||||
.withStates()
|
||||
.parent("SFork")
|
||||
.initial("Sub2-1")
|
||||
.end("Sub2-2");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
|
||||
transitions.withExternal()
|
||||
.source("SI").target("SFork").event("E1")
|
||||
.and().withExternal()
|
||||
.source("Sub1-1").target("Sub1-2").event("sub1")
|
||||
.and().withExternal()
|
||||
.source("Sub2-1").target("Sub2-2").event("sub2")
|
||||
.and()
|
||||
.withFork()
|
||||
.source("SFork")
|
||||
.target("Sub1-1")
|
||||
.target("Sub2-1")
|
||||
.and()
|
||||
.withJoin()
|
||||
.source("Sub1-2")
|
||||
.source("Sub2-2")
|
||||
.target("SJoin");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<String, String> mediumGuard() {
|
||||
return (ctx) -> false;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<String, String> highGuard() {
|
||||
return (ctx) -> false;
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.baeldung.spring.stateMachine.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
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;
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public class HierarchicalStateMachineConfiguration extends StateMachineConfigurerAdapter<String, String> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<String, String> config)
|
||||
throws Exception {
|
||||
config
|
||||
.withConfiguration()
|
||||
.autoStartup(true)
|
||||
.listener(new StateMachineListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial("SI")
|
||||
.state("SI")
|
||||
.end("SF")
|
||||
.and()
|
||||
.withStates()
|
||||
.parent("SI")
|
||||
.initial("SUB1")
|
||||
.state("SUB2")
|
||||
.end("SUBEND");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
|
||||
transitions.withExternal()
|
||||
.source("SI").target("SF").event("end")
|
||||
.and().withExternal()
|
||||
.source("SUB1").target("SUB2").event("se1")
|
||||
.and().withExternal()
|
||||
.source("SUB2").target("SUBEND").event("s-end");
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.baeldung.spring.stateMachine.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
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
|
||||
@EnableStateMachine
|
||||
public class JunctionStateMachineConfiguration extends StateMachineConfigurerAdapter<String, String> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<String, String> config)
|
||||
throws Exception {
|
||||
config
|
||||
.withConfiguration()
|
||||
.autoStartup(true)
|
||||
.listener(new StateMachineListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial("SI")
|
||||
.junction("SJ")
|
||||
.state("high")
|
||||
.state("medium")
|
||||
.state("low")
|
||||
.end("SF");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
|
||||
transitions.withExternal()
|
||||
.source("SI").target("SJ").event("E1")
|
||||
.and()
|
||||
.withJunction()
|
||||
.source("SJ")
|
||||
.first("high", highGuard())
|
||||
.then("medium", mediumGuard())
|
||||
.last("low")
|
||||
.and().withExternal()
|
||||
.source("low").target("SF").event("end");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<String, String> mediumGuard() {
|
||||
return (ctx) -> false;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<String, String> highGuard() {
|
||||
return (ctx) -> false;
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package com.baeldung.spring.stateMachine.config;
|
||||
|
||||
import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewEvents;
|
||||
import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewStates;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
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.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public class SimpleEnumStateMachineConfiguration extends StateMachineConfigurerAdapter<ApplicationReviewStates, ApplicationReviewEvents> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<ApplicationReviewStates, ApplicationReviewEvents> config)
|
||||
throws Exception {
|
||||
config
|
||||
.withConfiguration()
|
||||
.autoStartup(true)
|
||||
.listener(new StateMachineListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<ApplicationReviewStates, ApplicationReviewEvents> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(ApplicationReviewStates.PEER_REVIEW)
|
||||
.state(ApplicationReviewStates.PRINCIPAL_REVIEW)
|
||||
.end(ApplicationReviewStates.APPROVED)
|
||||
.end(ApplicationReviewStates.REJECTED);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<ApplicationReviewStates, ApplicationReviewEvents> transitions) throws Exception {
|
||||
transitions.withExternal()
|
||||
.source(ApplicationReviewStates.PEER_REVIEW).target(ApplicationReviewStates.PRINCIPAL_REVIEW).event(ApplicationReviewEvents.APPROVE)
|
||||
.and().withExternal()
|
||||
.source(ApplicationReviewStates.PRINCIPAL_REVIEW).target(ApplicationReviewStates.APPROVED).event(ApplicationReviewEvents.APPROVE)
|
||||
.and().withExternal()
|
||||
.source(ApplicationReviewStates.PEER_REVIEW).target(ApplicationReviewStates.REJECTED).event(ApplicationReviewEvents.REJECT)
|
||||
.and().withExternal()
|
||||
.source(ApplicationReviewStates.PRINCIPAL_REVIEW).target(ApplicationReviewStates.REJECTED).event(ApplicationReviewEvents.REJECT);
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.baeldung.spring.stateMachine.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
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
|
||||
@EnableStateMachine
|
||||
public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapter<String, String> {
|
||||
|
||||
public static final Logger LOGGER = Logger.getLogger(SimpleStateMachineConfiguration.class.getName());
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigurationConfigurer<String, String> config)
|
||||
throws Exception {
|
||||
config
|
||||
.withConfiguration()
|
||||
.autoStartup(true)
|
||||
.listener(new StateMachineListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial("SI")
|
||||
.end("SF")
|
||||
.states(new HashSet<>(Arrays.asList("S1", "S2")))
|
||||
.state("S4", executeAction(), errorAction())
|
||||
.stateEntry("S3", entryAction())
|
||||
.stateDo("S3", executeAction())
|
||||
.stateExit("S3", exitAction());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
|
||||
transitions.withExternal()
|
||||
.source("SI").target("S1").event("E1").action(initAction())
|
||||
.and().withExternal()
|
||||
.source("S1").target("S2").event("E2")
|
||||
.and().withExternal()
|
||||
.source("SI").target("S3").event("E3")
|
||||
.and().withExternal()
|
||||
.source("S3").target("S4").event("E4").and().withExternal().source("S4").target("SF").event("end").guard(simpleGuard())
|
||||
.and().withExternal()
|
||||
.source("S2").target("SF").event("end");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<String, String> simpleGuard() {
|
||||
return (ctx) -> {
|
||||
int approvalCount = (int) ctx.getExtendedState().getVariables().getOrDefault("approvalCount", 0);
|
||||
return approvalCount > 0;
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<String, String> entryAction() {
|
||||
return (ctx) -> {
|
||||
LOGGER.info("Entry " + ctx.getTarget().getId());
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<String, String> executeAction() {
|
||||
return (ctx) -> {
|
||||
LOGGER.info("Do " + ctx.getTarget().getId());
|
||||
int approvals = (int) ctx.getExtendedState().getVariables().getOrDefault("approvalCount", 0);
|
||||
approvals++;
|
||||
ctx.getExtendedState().getVariables().put("approvalCount", approvals);
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<String, String> exitAction() {
|
||||
return (ctx) -> {
|
||||
LOGGER.info("Exit " + ctx.getSource().getId() + " -> " + ctx.getTarget().getId());
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<String, String> errorAction() {
|
||||
return (ctx) -> {
|
||||
LOGGER.info("Error " + ctx.getSource().getId() + ctx.getException());
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<String, String> initAction() {
|
||||
return (ctx) -> {
|
||||
LOGGER.info(ctx.getTarget().getId());
|
||||
};
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.spring.stateMachine.config;
|
||||
|
||||
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class StateMachineListener extends StateMachineListenerAdapter {
|
||||
|
||||
public static final Logger LOGGER = Logger.getLogger(StateMachineListener.class.getName());
|
||||
|
||||
@Override
|
||||
public void stateChanged(State from, State to) {
|
||||
LOGGER.info(String.format("Transitioned from %s to %s%n", from == null ? "none" : from.getId(), to.getId()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user