BAEL-3091: The Prototype Pattern in Java (changed code based on valid comments from a reader)

This commit is contained in:
Vivek Balasubramaniam
2019-10-29 22:27:15 +05:30
parent db85c8f275
commit d3d5b060e7
20517 changed files with 1642290 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
## Spring State Machine
This module contains articles about Spring State Machine
### Relevant articles
- [A Guide to the Spring State Machine Project](https://www.baeldung.com/spring-state-machine)
+116
View File
@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1489770331405" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="myProcess_1" isClosed="false" isExecutable="true" processType="None">
<startEvent id="_2" name="Start">
<messageEventDefinition id="_2_ED_1"/>
</startEvent>
<parallelGateway gatewayDirection="Unspecified" id="_3" name="Fork"/>
<userTask activiti:exclusive="true" id="_4" name="UserTask"/>
<scriptTask activiti:exclusive="true" id="_5" name="ScriptTask"/>
<endEvent id="_7" name="EndEvent">
<terminateEventDefinition id="_7_ED_1"/>
<extensionElements>
<activiti:executionListener event="start">
<activiti:field>
<activiti:string/>
</activiti:field>
</activiti:executionListener>
<activiti:executionListener event="start"/>
<activiti:executionListener event="start"/>
<activiti:executionListener event="start"/>
<activiti:executionListener event="start"/>
</extensionElements>
</endEvent>
<inclusiveGateway gatewayDirection="Unspecified" id="_6" name="Join"/>
<sequenceFlow id="_8" sourceRef="_3" targetRef="_4"/>
<sequenceFlow id="_9" sourceRef="_3" targetRef="_5"/>
<sequenceFlow id="_10" sourceRef="_5" targetRef="_6"/>
<sequenceFlow id="_11" sourceRef="_4" targetRef="_6"/>
<sequenceFlow id="_12" sourceRef="_6" targetRef="_7"/>
<sequenceFlow id="_13" sourceRef="_2" targetRef="_3"/>
</process>
<bpmndi:BPMNDiagram documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="myProcess_1">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<omgdc:Bounds height="32.0" width="32.0" x="35.0" y="95.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
<omgdc:Bounds height="32.0" width="32.0" x="140.0" y="95.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
<omgdc:Bounds height="55.0" width="85.0" x="230.0" y="20.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
<omgdc:Bounds height="55.0" width="85.0" x="230.0" y="180.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7">
<omgdc:Bounds height="32.0" width="32.0" x="475.0" y="130.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
<omgdc:Bounds height="32.0" width="32.0" x="375.0" y="130.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="_2" targetElement="_3">
<omgdi:waypoint x="67.0" y="111.0"/>
<omgdi:waypoint x="140.0" y="111.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_6" targetElement="_7">
<omgdi:waypoint x="407.0" y="146.0"/>
<omgdi:waypoint x="475.0" y="146.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_3" targetElement="_4">
<omgdi:waypoint x="172.0" y="111.0"/>
<omgdi:waypoint x="230.0" y="47.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_3" targetElement="_5">
<omgdi:waypoint x="172.0" y="111.0"/>
<omgdi:waypoint x="230.0" y="207.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="_4" targetElement="_6">
<omgdi:waypoint x="315.0" y="45.0"/>
<omgdi:waypoint x="390.0" y="45.0"/>
<omgdi:waypoint x="390.0" y="131.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_5" targetElement="_6">
<omgdi:waypoint x="315.0" y="190.0"/>
<omgdi:waypoint x="355.0" y="190.0"/>
<omgdi:waypoint x="375.0" y="146.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

+76
View File
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1489503806724" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="myProcess_1" isClosed="false" isExecutable="true" processType="None">
<startEvent id="_2" name="SI">
<messageEventDefinition id="_2_ED_1"/>
</startEvent>
<userTask activiti:exclusive="true" id="_3" name="S1"/>
<userTask activiti:exclusive="true" id="_4" name="S2"/>
<endEvent id="_5" name="SF">
<terminateEventDefinition id="_5_ED_1"/>
<extensionElements>
<activiti:executionListener event="start">
<activiti:field>
<activiti:string/>
</activiti:field>
</activiti:executionListener>
<activiti:executionListener event="start"/>
<activiti:executionListener event="start"/>
<activiti:executionListener event="start"/>
<activiti:executionListener event="start"/>
</extensionElements>
</endEvent>
<sequenceFlow id="_6" sourceRef="_2" targetRef="_3"/>
<sequenceFlow id="_7" sourceRef="_3" targetRef="_4"/>
<sequenceFlow id="_8" sourceRef="_4" targetRef="_5"/>
</process>
<bpmndi:BPMNDiagram documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="myProcess_1">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<omgdc:Bounds height="32.0" width="32.0" x="85.0" y="95.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
<omgdc:Bounds height="40.0" width="75.0" x="180.0" y="105.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="40.0" width="75.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
<omgdc:Bounds height="40.0" width="70.0" x="320.0" y="105.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="40.0" width="70.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
<omgdc:Bounds height="32.0" width="32.0" x="460.0" y="95.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_6" id="BPMNEdge__6" sourceElement="_2" targetElement="_3">
<omgdi:waypoint x="117.0" y="111.0"/>
<omgdi:waypoint x="180.0" y="125.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7" sourceElement="_3" targetElement="_4">
<omgdi:waypoint x="255.0" y="125.0"/>
<omgdi:waypoint x="320.0" y="125.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_4" targetElement="_5">
<omgdi:waypoint x="390.0" y="125.0"/>
<omgdi:waypoint x="460.0" y="111.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
+39
View File
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-state-machine</artifactId>
<name>spring-state-machine</name>
<parent>
<artifactId>parent-modules</artifactId>
<groupId>com.baeldung</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>${spring-statemachine-core.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-test.version}</version>
</dependency>
<dependency>
<groupId>com.jayway.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>${jayway.awaitility.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<spring-statemachine-core.version>1.2.3.RELEASE</spring-statemachine-core.version>
<spring-test.version>4.3.7.RELEASE</spring-test.version>
<jayway.awaitility.version>1.7.0</jayway.awaitility.version>
</properties>
</project>
@@ -0,0 +1,5 @@
package com.baeldung.spring.statemachine.applicationreview;
public enum ApplicationReviewEvents {
APPROVE, REJECT
}
@@ -0,0 +1,5 @@
package com.baeldung.spring.statemachine.applicationreview;
public enum ApplicationReviewStates {
PEER_REVIEW, PRINCIPAL_REVIEW, APPROVED, REJECTED
}
@@ -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;
}
}
@@ -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");
}
}
@@ -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;
}
}
@@ -0,0 +1,47 @@
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.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 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);
}
}
@@ -0,0 +1,146 @@
package com.baeldung.spring.statemachine.config;
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;
import java.util.logging.Logger;
@Configuration
@EnableStateMachine
public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapter<String, String> {
private 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")))
.stateEntry("S3", entryAction())
.stateExit("S3", exitAction())
.state("S4", executeAction(), errorAction())
.stateDo("S5", executeAction());
}
@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("S5")
.event("E5")
.and()
.withExternal()
.source("S5")
.target("SF")
.event("end")
.guard(simpleGuard());
}
@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> doAction() {
return ctx -> LOGGER.info("Do " + ctx
.getTarget()
.getId());
}
@Bean
public Action<String, String> executeAction() {
return ctx -> {
LOGGER.info("Execute " + 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());
}
}
@@ -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 {
private 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()));
}
}
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,57 @@
package com.baeldung.spring.statemachine;
import com.baeldung.spring.statemachine.config.ForkJoinStateMachineConfiguration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ForkJoinStateMachineConfiguration.class)
public class ForkJoinStateMachineIntegrationTest {
@Autowired
private StateMachine<String, String> stateMachine;
@Before
public void setUp() {
stateMachine.start();
}
@Test
public void whenForkStateEntered_thenMultipleSubStatesEntered() {
boolean success = stateMachine.sendEvent("E1");
assertTrue(success);
assertTrue(Arrays.asList("SFork", "Sub1-1", "Sub2-1").containsAll(stateMachine.getState().getIds()));
}
@Test
public void whenAllConfiguredJoinEntryStatesAreEntered_thenTransitionToJoinState() {
boolean success = stateMachine.sendEvent("E1");
assertTrue(success);
assertTrue(Arrays.asList("SFork", "Sub1-1", "Sub2-1").containsAll(stateMachine.getState().getIds()));
assertTrue(stateMachine.sendEvent("sub1"));
assertTrue(stateMachine.sendEvent("sub2"));
assertEquals("SJoin", stateMachine.getState().getId());
}
@After
public void tearDown() {
stateMachine.stop();
}
}
@@ -0,0 +1,52 @@
package com.baeldung.spring.statemachine;
import com.baeldung.spring.statemachine.config.HierarchicalStateMachineConfiguration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = HierarchicalStateMachineConfiguration.class)
public class HierarchicalStateMachineIntegrationTest {
@Autowired
private StateMachine<String, String> stateMachine;
@Before
public void setUp() {
stateMachine.start();
}
@Test
public void whenTransitionToSubMachine_thenSubStateIsEntered() {
assertEquals(Arrays.asList("SI", "SUB1"), stateMachine.getState().getIds());
stateMachine.sendEvent("se1");
assertEquals(Arrays.asList("SI", "SUB2"), stateMachine.getState().getIds());
stateMachine.sendEvent("s-end");
assertEquals(Arrays.asList("SI", "SUBEND"), stateMachine.getState().getIds());
stateMachine.sendEvent("end");
assertEquals(1, stateMachine.getState().getIds().size());
assertEquals("SF", stateMachine.getState().getId());
}
@After
public void tearDown() {
stateMachine.stop();
}
}
@@ -0,0 +1,40 @@
package com.baeldung.spring.statemachine;
import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = JunctionStateMachineConfiguration.class)
public class JunctionStateMachineIntegrationTest {
@Autowired
private StateMachine<String, String> stateMachine;
@Before
public void setUp() {
stateMachine.start();
}
@Test
public void whenTransitioningToJunction_thenArriveAtSubJunctionNode() {
stateMachine.sendEvent("E1");
Assert.assertEquals("low", stateMachine.getState().getId());
stateMachine.sendEvent("end");
Assert.assertEquals("SF", stateMachine.getState().getId());
}
@After
public void tearDown() {
stateMachine.stop();
}
}
@@ -0,0 +1,42 @@
package com.baeldung.spring.statemachine;
import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewEvents;
import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewStates;
import com.baeldung.spring.statemachine.config.SimpleEnumStateMachineConfiguration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SimpleEnumStateMachineConfiguration.class)
public class StateEnumMachineIntegrationTest {
@Autowired
private StateMachine<ApplicationReviewStates, ApplicationReviewEvents> stateMachine;
@Before
public void setUp() {
stateMachine.start();
}
@Test
public void whenStateMachineConfiguredWithEnums_thenStateMachineAcceptsEnumEvents() {
assertTrue(stateMachine.sendEvent(ApplicationReviewEvents.APPROVE));
assertEquals(ApplicationReviewStates.PRINCIPAL_REVIEW, stateMachine.getState().getId());
assertTrue(stateMachine.sendEvent(ApplicationReviewEvents.REJECT));
assertEquals(ApplicationReviewStates.REJECTED, stateMachine.getState().getId());
}
@After
public void tearDown() {
stateMachine.stop();
}
}
@@ -0,0 +1,35 @@
package com.baeldung.spring.statemachine;
import org.junit.Test;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineBuilder;
import static org.junit.Assert.assertEquals;
public class StateMachineBuilderIntegrationTest {
@Test
public void whenUseStateMachineBuilder_thenBuildSuccessAndMachineWorks() throws Exception {
StateMachineBuilder.Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureStates().withStates()
.initial("SI")
.state("S1")
.end("SF");
builder.configureTransitions()
.withExternal()
.source("SI").target("S1").event("E1")
.and().withExternal()
.source("S1").target("SF").event("E2");
StateMachine machine = builder.build();
machine.start();
machine.sendEvent("E1");
assertEquals("S1", machine.getState().getId());
machine.sendEvent("E2");
assertEquals("SF", machine.getState().getId());
}
}
@@ -0,0 +1,63 @@
package com.baeldung.spring.statemachine;
import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SimpleStateMachineConfiguration.class)
public class StateMachineIntegrationTest {
@Autowired
private StateMachine<String, String> stateMachine;
@Before
public void setUp() {
stateMachine.start();
}
@Test
public void whenSimpleStringStateMachineEvents_thenEndState() {
assertEquals("SI", stateMachine.getState().getId());
stateMachine.sendEvent("E1");
assertEquals("S1", stateMachine.getState().getId());
stateMachine.sendEvent("E2");
assertEquals("S2", stateMachine.getState().getId());
}
@Test
public void whenSimpleStringMachineActionState_thenActionExecuted() {
stateMachine.sendEvent("E3");
assertEquals("S3", stateMachine.getState().getId());
boolean acceptedE4 = stateMachine.sendEvent("E4");
assertTrue(acceptedE4);
assertEquals("S4", stateMachine.getState().getId());
stateMachine.sendEvent("E5");
assertEquals("S5", stateMachine.getState().getId());
stateMachine.sendEvent("end");
assertEquals("SF", stateMachine.getState().getId());
assertEquals(2, stateMachine.getExtendedState().getVariables().get("approvalCount"));
}
@After
public void tearDown() {
stateMachine.stop();
}
}
@@ -0,0 +1,23 @@
package org.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.baeldung.spring.statemachine.config.ForkJoinStateMachineConfiguration;
import com.baeldung.spring.statemachine.config.HierarchicalStateMachineConfiguration;
import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration;
import com.baeldung.spring.statemachine.config.SimpleEnumStateMachineConfiguration;
import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { SimpleStateMachineConfiguration.class, SimpleEnumStateMachineConfiguration.class,
JunctionStateMachineConfiguration.class, HierarchicalStateMachineConfiguration.class,
ForkJoinStateMachineConfiguration.class })
public class SpringContextIntegrationTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,23 @@
package org.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.baeldung.spring.statemachine.config.ForkJoinStateMachineConfiguration;
import com.baeldung.spring.statemachine.config.HierarchicalStateMachineConfiguration;
import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration;
import com.baeldung.spring.statemachine.config.SimpleEnumStateMachineConfiguration;
import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { SimpleStateMachineConfiguration.class, SimpleEnumStateMachineConfiguration.class,
JunctionStateMachineConfiguration.class, HierarchicalStateMachineConfiguration.class,
ForkJoinStateMachineConfiguration.class })
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}