Updates to docs
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,6 +5,7 @@ build
|
||||
.classpath
|
||||
.project
|
||||
*.iml
|
||||
*.log
|
||||
*.ipr
|
||||
*.iws
|
||||
metastore_db
|
||||
|
||||
26
build.gradle
26
build.gradle
@@ -7,6 +7,13 @@ buildscript {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
|
||||
classpath('org.asciidoctor:asciidoctor-gradle-plugin:1.5.2')
|
||||
classpath("io.spring.gradle:docbook-reference-plugin:0.3.0")
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.1.RELEASE")
|
||||
}
|
||||
}
|
||||
|
||||
def sampleProjects() {
|
||||
subprojects.findAll { project ->
|
||||
project.name.contains('spring-statemachine-samples') && project.name != 'spring-statemachine-samples-common'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +111,21 @@ project('spring-statemachine-core') {
|
||||
}
|
||||
}
|
||||
|
||||
configure(sampleProjects()) {
|
||||
apply plugin: 'spring-boot'
|
||||
dependencies {
|
||||
compile project(":spring-statemachine-samples-common")
|
||||
}
|
||||
}
|
||||
|
||||
project('spring-statemachine-samples-common') {
|
||||
dependencies {
|
||||
compile project(":spring-statemachine-core")
|
||||
compile "org.springframework.shell:spring-shell:1.1.0.RELEASE"
|
||||
compile "org.springframework.boot:spring-boot-starter:1.2.1.RELEASE"
|
||||
}
|
||||
}
|
||||
|
||||
configure(rootProject) {
|
||||
description = 'Spring State Machine'
|
||||
|
||||
@@ -152,7 +174,9 @@ configure(rootProject) {
|
||||
|
||||
task copyDocsSamples(type: Copy) {
|
||||
from 'spring-statemachine-core/src/test/java/org/springframework/statemachine/docs'
|
||||
include '*.java'
|
||||
from 'spring-statemachine-samples/src/main/java/'
|
||||
from 'spring-statemachine-samples/turnstile/src/main/java/'
|
||||
include '**/*.java'
|
||||
into 'docs/src/reference/asciidoc/samples'
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ material in this reference documentation.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/MyStates.java[tags=snippetA]
|
||||
include::samples/States.java[tags=snippetA]
|
||||
----
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/MyEvents.java[tags=snippetA]
|
||||
include::samples/Events.java[tags=snippetA]
|
||||
----
|
||||
|
||||
[appendix]
|
||||
@@ -28,55 +28,56 @@ This appendix provides generic information about state machines.
|
||||
[glossary]
|
||||
=== Glossary
|
||||
|
||||
State Machine::
|
||||
*State Machine*::
|
||||
Main entity driving a collection of states together with regions,
|
||||
transitions and events.
|
||||
|
||||
State::
|
||||
*State*::
|
||||
A state models a situation during which some invariant condition
|
||||
holds. State is the main entity of a state machine where state changes
|
||||
are driven by an events.
|
||||
|
||||
Transition::
|
||||
*Transition*::
|
||||
A transition is a relationship between a source state and a target
|
||||
state. It may be part of a compound transition, which takes the state
|
||||
machine from one state configuration to another, representing the complete
|
||||
response of the state machine to an occurrence of an event of a
|
||||
particular type.
|
||||
|
||||
Event::
|
||||
*Event*::
|
||||
An entity which is send to a state machine which then drives a various
|
||||
state changes.
|
||||
|
||||
Initial State::
|
||||
*Initial State*::
|
||||
A special state in which the state machine starts. Initial state is
|
||||
always bound to a particulal state machine or a region. A state
|
||||
machine with a multiple regions may have a multiple initial states.
|
||||
|
||||
End State::
|
||||
*End State*::
|
||||
Also called as a final state is a special kind of state signifying
|
||||
that the enclosing region is completed. If the enclosing region is
|
||||
directly contained in a state machine and all other regions in the
|
||||
state machine also are completed, then it means that the entire state
|
||||
machine is completed.
|
||||
|
||||
Region::
|
||||
*Region*::
|
||||
A region is an orthogonal part of either a composite state or a state
|
||||
machine. It contains states and transitions.
|
||||
|
||||
Guard::
|
||||
*Guard*::
|
||||
Is a boolean expression evaluated dynamically based on the value of
|
||||
extended state variables and event parameters. Guard conditions affect
|
||||
the behavior of a state machine by enabling actions or transitions
|
||||
only when they evaluate to TRUE and disabling them when they evaluate
|
||||
to FALSE.
|
||||
|
||||
Action::
|
||||
*Action*::
|
||||
A action is a behaviour executed during the triggering of the
|
||||
transition.
|
||||
|
||||
=== A State Machines Crash Course
|
||||
TBD.
|
||||
This appendix provides generic crash course to a state machine
|
||||
concepts.
|
||||
|
||||
==== States
|
||||
TBD.
|
||||
|
||||
BIN
docs/src/reference/asciidoc/images/statechart1.png
Normal file
BIN
docs/src/reference/asciidoc/images/statechart1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
@@ -1,6 +1,9 @@
|
||||
[[introduction]]
|
||||
= Introduction
|
||||
|
||||
Spring State Machine(SSM) is a framework for application developers to
|
||||
use state machine concepts with Spring.
|
||||
|
||||
== Requirements
|
||||
|
||||
Spring Statemachine {revnumber} is built and tested with JDK 7, Spring
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
[preface]
|
||||
== Preface
|
||||
Spring State Machine(SSM) is a framework for application developers to use
|
||||
state machine concepts with Spring.
|
||||
|
||||
Concept of a state machine is most likely older that any of a reader
|
||||
of this reference documentation and definitely older than a Java
|
||||
language itself. Description of finite automate dates back to 1943
|
||||
|
||||
@@ -1,10 +1,77 @@
|
||||
[[statemachine-examples]]
|
||||
= Statemachine Examples
|
||||
= State Machine Examples
|
||||
|
||||
This part of the reference documentation explains the use of state
|
||||
machines as sample code together with a uml state charts.
|
||||
machines as sample code together with a uml state charts. We do few
|
||||
shortcuts when representing relationship between a state chart, SSM
|
||||
configuration and what an application does with a state machine. For
|
||||
complete examples go and study the samples repository.
|
||||
|
||||
== Simple Statemachine
|
||||
== Turnstile
|
||||
|
||||
TBD
|
||||
Turnstile is a simple device which gives you an access if payment is
|
||||
made and is a very simple to model using a state machine. In its
|
||||
simples form there are only two states, `LOCKED` and `UNLOCKED`. Two
|
||||
events, `COIN` and `PUSH` can happen if you try to go through it or
|
||||
you make a payment.
|
||||
|
||||
image::images/statechart1.png[]
|
||||
|
||||
.States
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/demo/turnstile/Application.java[tags=snippetB]
|
||||
----
|
||||
|
||||
.Events
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/demo/turnstile/Application.java[tags=snippetC]
|
||||
----
|
||||
|
||||
.Configuration
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/demo/turnstile/Application.java[tags=snippetA]
|
||||
----
|
||||
|
||||
You can see how this sample state machine interacts with event by
|
||||
running `turnstile` sample.
|
||||
[source,text]
|
||||
----
|
||||
$ java -jar spring-statemachine-samples-turnstile-1.0.0.BUILD-SNAPSHOT.jar
|
||||
|
||||
sm>sm print
|
||||
+----------------------------------------------------------------+
|
||||
| SM |
|
||||
+----------------------------------------------------------------+
|
||||
| |
|
||||
| +----------------+ +----------------+ |
|
||||
| *-->| LOCKED | | UNLOCKED | |
|
||||
| +----------------+ +----------------+ |
|
||||
| +---| entry/ | | entry/ |---+ |
|
||||
| | | exit/ | | exit/ | | |
|
||||
| | | | | | | |
|
||||
| PUSH| | |---COIN-->| | |COIN |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | |<--PUSH---| | | |
|
||||
| +-->| | | |<--+ |
|
||||
| | | | | |
|
||||
| +----------------+ +----------------+ |
|
||||
| |
|
||||
+----------------------------------------------------------------+
|
||||
|
||||
sm>sm start
|
||||
State changed to LOCKED
|
||||
State machine started
|
||||
|
||||
sm>sm event COIN
|
||||
State changed to UNLOCKED
|
||||
Event COIN send
|
||||
|
||||
sm>sm event PUSH
|
||||
State changed to LOCKED
|
||||
Event PUSH send
|
||||
----
|
||||
|
||||
|
||||
@@ -6,24 +6,93 @@ that Spring Statemachine provides to any Spring based application.
|
||||
|
||||
<<sm-config>> describes the generic configuration support.
|
||||
|
||||
<<sm-factories>> describes the generic state machine factory support.
|
||||
|
||||
<<sm-listeners>> describes the generic state machine listener support.
|
||||
|
||||
<<sm-context>> describes the generic Spring application context support.
|
||||
|
||||
[[sm-config]]
|
||||
== Statemachine Configuration
|
||||
|
||||
One of the common tasks when using a Statemachine is to design its
|
||||
runtime configuration. This chapter will focus on How Spring
|
||||
runtime configuration. This chapter will focus on how Spring
|
||||
Statemachine is configured and how it leverages Spring's lightweight
|
||||
IoC containers to simplify the application internals to make it more
|
||||
manageable.
|
||||
|
||||
=== Using the Spring Statemachine JavaConfig
|
||||
=== Configuring States
|
||||
|
||||
We'll get into more complex configuration examples a bit later but
|
||||
lets first start with a something simple. For most simple state
|
||||
machine you
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippetA]
|
||||
----
|
||||
|
||||
=== Configuring Hierarchical States
|
||||
|
||||
== Context Ingregration
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippetB]
|
||||
----
|
||||
|
||||
=== Configuring Transitions
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippetC]
|
||||
----
|
||||
|
||||
=== Configuring Guards
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippetD]
|
||||
----
|
||||
|
||||
=== Configuring Actions
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippetE]
|
||||
----
|
||||
|
||||
[[sm-factories]]
|
||||
== State Machine Factories
|
||||
There are use cases when state machine needs to be created dynamically
|
||||
instead of defining static configuration at compile time. For example
|
||||
if there are custom components which are using its own state machines
|
||||
and these components are created dynamically it is impossible to have
|
||||
a static state machined build during the application start. Internally
|
||||
state machines are always build via a factory interfaces and this then
|
||||
gives user an option to use this feature programmatically.
|
||||
Configuration for state machine factory is exactly same as you've seen
|
||||
in various examples in this document where state machine configuration
|
||||
is hard coded.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippetF]
|
||||
----
|
||||
|
||||
=== Factory Limitations
|
||||
|
||||
xxx
|
||||
|
||||
[[sm-listeners]]
|
||||
== State Machine Listeners
|
||||
|
||||
There are use cases where you just want to know what is happening with
|
||||
a state machine, react to something or simply get logging for
|
||||
debugging purposes. SSM provides interfaces for adding listeners which
|
||||
then gives an option to get callback when various state changes,
|
||||
actions, etc are happening.
|
||||
|
||||
[[sm-context]]
|
||||
== Context Integration
|
||||
|
||||
TBD
|
||||
|
||||
@@ -31,3 +100,9 @@ TBD
|
||||
|
||||
TBD
|
||||
|
||||
=== Context Events
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippetG]
|
||||
----
|
||||
|
||||
19
docs/src/statecharts/statechart1.txt
Normal file
19
docs/src/statecharts/statechart1.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
+----------------------------------------------------------------+
|
||||
| SM |
|
||||
+----------------------------------------------------------------+
|
||||
| |
|
||||
| +----------------+ +----------------+ |
|
||||
| *-->| LOCKED | | UNLOCKED | |
|
||||
| +----------------+ +----------------+ |
|
||||
| +---| entry/ | | entry/ |---+ |
|
||||
| | | exit/ | | exit/ | | |
|
||||
| | | | | | | |
|
||||
| PUSH| | |---COIN-->| | |COIN |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | |<--PUSH---| | | |
|
||||
| +-->| | | |<--+ |
|
||||
| | | | | |
|
||||
| +----------------+ +----------------+ |
|
||||
| |
|
||||
+----------------------------------------------------------------+
|
||||
@@ -1,3 +1,16 @@
|
||||
rootProject.name = 'spring-statemachine'
|
||||
|
||||
include 'spring-statemachine-core'
|
||||
|
||||
include 'spring-statemachine-samples'
|
||||
include 'spring-statemachine-samples:turnstile'
|
||||
|
||||
rootProject.children.find {
|
||||
if (it.name == 'spring-statemachine-samples') {
|
||||
it.name = 'spring-statemachine-samples-common'
|
||||
it.children.each {
|
||||
it.name = 'spring-statemachine-samples-' + it.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,19 @@ package org.springframework.statemachine.docs;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.event.StateMachineEvent;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
|
||||
/**
|
||||
* Tests for state machine configuration.
|
||||
@@ -34,18 +42,155 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests {
|
||||
// tag::snippetA[]
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public static class Config1 extends EnumStateMachineConfigurerAdapter<MyStates, MyEvents> {
|
||||
public static class Config1 extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<MyStates, MyEvents> states) throws Exception {
|
||||
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(MyStates.S1)
|
||||
.end(MyStates.SF)
|
||||
.states(EnumSet.allOf(MyStates.class));
|
||||
.initial(States.S1)
|
||||
.end(States.SF)
|
||||
.states(EnumSet.allOf(States.class));
|
||||
}
|
||||
|
||||
}
|
||||
// end::snippetA[]
|
||||
|
||||
// tag::snippetB[]
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public static class Config2 extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(States.S1)
|
||||
.end(States.SF)
|
||||
.states(EnumSet.allOf(States.class))
|
||||
.and()
|
||||
.withStates()
|
||||
.initial(States.S2)
|
||||
.state(States.S2);
|
||||
}
|
||||
|
||||
}
|
||||
// end::snippetB[]
|
||||
|
||||
// tag::snippetC[]
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public static class Config3 extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(States.S1)
|
||||
.end(States.SF)
|
||||
.states(EnumSet.allOf(States.class))
|
||||
.and()
|
||||
.withStates()
|
||||
.initial(States.S2)
|
||||
.state(States.S2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.and()
|
||||
.withInternal()
|
||||
.and()
|
||||
.withLocal();
|
||||
}
|
||||
|
||||
}
|
||||
// end::snippetC[]
|
||||
|
||||
// tag::snippetD[]
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public static class Config4 extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(States.S1)
|
||||
.target(States.S2)
|
||||
.event(Events.E1)
|
||||
.guard(guard());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<States, Events> guard() {
|
||||
return new Guard<States, Events>() {
|
||||
|
||||
@Override
|
||||
public boolean evaluate(StateContext<States, Events> context) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
// end::snippetD[]
|
||||
|
||||
// tag::snippetE[]
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public static class Config5 extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(States.S1)
|
||||
.target(States.S2)
|
||||
.event(Events.E1)
|
||||
.action(action());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<States, Events> action() {
|
||||
return new Action<States, Events>() {
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<States, Events> context) {
|
||||
// do something
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
// end::snippetE[]
|
||||
|
||||
// tag::snippetF[]
|
||||
@Configuration
|
||||
@EnableStateMachineFactory
|
||||
public static class Config6 extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(States.S1)
|
||||
.end(States.SF)
|
||||
.states(EnumSet.allOf(States.class));
|
||||
}
|
||||
|
||||
}
|
||||
// end::snippetF[]
|
||||
|
||||
|
||||
// tag::snippetG[]
|
||||
static class StateMachineEventListener implements ApplicationListener<StateMachineEvent> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(StateMachineEvent event) {
|
||||
}
|
||||
}
|
||||
// end::snippetG[]
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.springframework.statemachine.docs;
|
||||
|
||||
//tag::snippetA[]
|
||||
public enum MyEvents {
|
||||
public enum Events {
|
||||
E1,E2,E3,E4,EF
|
||||
}
|
||||
//end::snippetA[]
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.springframework.statemachine.docs;
|
||||
|
||||
//tag::snippetA[]
|
||||
public enum MyStates {
|
||||
public enum States {
|
||||
SI,S1,S2,S3,S4,SF
|
||||
}
|
||||
//end::snippetA[]
|
||||
6
spring-statemachine-samples/build.gradle
Normal file
6
spring-statemachine-samples/build.gradle
Normal file
@@ -0,0 +1,6 @@
|
||||
description = 'Spring State Machine Samples Common'
|
||||
|
||||
project('spring-statemachine-samples-turnstile') {
|
||||
description = 'Spring State Machine Turnstile Sample'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package demo;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.shell.core.CommandMarker;
|
||||
import org.springframework.shell.core.annotation.CliCommand;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@Component
|
||||
public class AbstractStateMachineCommands<S, E> implements CommandMarker {
|
||||
|
||||
@Autowired
|
||||
private StateMachine<S, E> stateMachine;
|
||||
|
||||
protected StateMachine<S, E> getStateMachine() {
|
||||
return stateMachine;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@Qualifier("stateChartModel")
|
||||
private String stateChartModel;
|
||||
|
||||
@CliCommand(value = "sm state", help = "Prints state machine state")
|
||||
public String state() {
|
||||
return StringUtils.collectionToCommaDelimitedString(stateMachine.getState().getIds());
|
||||
}
|
||||
|
||||
@CliCommand(value = "sm start", help = "Start a state machine")
|
||||
public String start() {
|
||||
stateMachine.start();
|
||||
return "State machine started";
|
||||
}
|
||||
|
||||
@CliCommand(value = "sm stop", help = "Stop a state machine")
|
||||
public String stop() {
|
||||
stateMachine.stop();
|
||||
return "State machine stopped";
|
||||
}
|
||||
|
||||
@CliCommand(value = "sm print", help = "Print state machine")
|
||||
public String print() {
|
||||
return stateChartModel;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package demo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.statemachine.event.OnStateChangedEvent;
|
||||
import org.springframework.statemachine.event.OnTransitionEvent;
|
||||
import org.springframework.statemachine.event.StateMachineEvent;
|
||||
import org.springframework.statemachine.event.StateMachineEventPublisherConfiguration;
|
||||
|
||||
@Configuration
|
||||
public class CommonConfiguration {
|
||||
|
||||
private final static Log log = LogFactory.getLog(CommonConfiguration.class);
|
||||
|
||||
@Configuration
|
||||
@Import(StateMachineEventPublisherConfiguration.class)
|
||||
static class ApplicationConfig {
|
||||
|
||||
@Bean
|
||||
public TaskExecutor taskExecutor() {
|
||||
return new SyncTaskExecutor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestEventListener testEventListener() {
|
||||
return new TestEventListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public String stateChartModel() throws IOException {
|
||||
ClassPathResource model = new ClassPathResource("statechartmodel.txt");
|
||||
InputStream inputStream = model.getInputStream();
|
||||
Scanner scanner = new Scanner(inputStream);
|
||||
String content = scanner.useDelimiter("\\Z").next();
|
||||
scanner.close();
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestEventListener implements ApplicationListener<StateMachineEvent> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(StateMachineEvent event) {
|
||||
if (event instanceof OnStateChangedEvent) {
|
||||
OnStateChangedEvent e = (OnStateChangedEvent)event;
|
||||
log.info("State changed to " + e.getTargetState().getId());
|
||||
} else if (event instanceof OnTransitionEvent) {
|
||||
OnTransitionEvent e = (OnTransitionEvent)event;
|
||||
log.info("Transition " + e.getTransition().toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package demo;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.shell.plugin.support.DefaultPromptProvider;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class StateMachinePromptProvider extends DefaultPromptProvider {
|
||||
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
return "sm>";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getProviderName() {
|
||||
return "State machine prompt provider";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
<context:component-scan base-package="demo" />
|
||||
</beans>
|
||||
17
spring-statemachine-samples/src/main/resources/logback.xml
Normal file
17
spring-statemachine-samples/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%m%n</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="WARN">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
</root>
|
||||
|
||||
<logger name="demo" level="INFO"/>
|
||||
|
||||
</configuration>
|
||||
19
spring-statemachine-samples/turnstile/.gitignore
vendored
Normal file
19
spring-statemachine-samples/turnstile/.gitignore
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
.gradle
|
||||
bin
|
||||
build
|
||||
.settings
|
||||
.classpath
|
||||
.springBeans
|
||||
.project
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
metastore_db
|
||||
/samples/pig-scripting/src/main/resources/ml-100k.zip
|
||||
/samples/pig-scripting/src/main/resources/ml-100k/u.data
|
||||
/src/test/resources/s3.properties
|
||||
/.idea/
|
||||
.DS_Store
|
||||
/out/
|
||||
target
|
||||
*.log
|
||||
@@ -0,0 +1,64 @@
|
||||
package demo.turnstile;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.shell.Bootstrap;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class Application {
|
||||
|
||||
//tag::snippetA[]
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class StateMachineConfig
|
||||
extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<States, Events> states)
|
||||
throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(States.LOCKED)
|
||||
.states(EnumSet.allOf(States.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
|
||||
throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(States.LOCKED)
|
||||
.target(States.UNLOCKED)
|
||||
.event(Events.COIN)
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(States.UNLOCKED)
|
||||
.target(States.LOCKED)
|
||||
.event(Events.PUSH);
|
||||
}
|
||||
|
||||
}
|
||||
//end::snippetA[]
|
||||
|
||||
//tag::snippetB[]
|
||||
public static enum States {
|
||||
LOCKED, UNLOCKED
|
||||
}
|
||||
//end::snippetB[]
|
||||
|
||||
//tag::snippetC[]
|
||||
public static enum Events {
|
||||
COIN, PUSH
|
||||
}
|
||||
//end::snippetC[]
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Bootstrap.main(args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package demo.turnstile;
|
||||
|
||||
import org.springframework.shell.core.annotation.CliCommand;
|
||||
import org.springframework.shell.core.annotation.CliOption;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import demo.AbstractStateMachineCommands;
|
||||
import demo.turnstile.Application.Events;
|
||||
import demo.turnstile.Application.States;
|
||||
|
||||
@Component
|
||||
public class StateMachineCommands extends AbstractStateMachineCommands<States, Events> {
|
||||
|
||||
@CliCommand(value = "sm event", help = "Sends an event to a state machine")
|
||||
public String event(@CliOption(key = { "", "event" }, mandatory = true, help = "The event") final Events event) {
|
||||
getStateMachine().sendEvent(event);
|
||||
return "Event " + event + " send";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
<context:component-scan base-package="demo" />
|
||||
</beans>
|
||||
@@ -0,0 +1,19 @@
|
||||
+----------------------------------------------------------------+
|
||||
| SM |
|
||||
+----------------------------------------------------------------+
|
||||
| |
|
||||
| +----------------+ +----------------+ |
|
||||
| *-->| LOCKED | | UNLOCKED | |
|
||||
| +----------------+ +----------------+ |
|
||||
| +---| entry/ | | entry/ |---+ |
|
||||
| | | exit/ | | exit/ | | |
|
||||
| | | | | | | |
|
||||
| PUSH| | |---COIN-->| | |COIN |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | |<--PUSH---| | | |
|
||||
| +-->| | | |<--+ |
|
||||
| | | | | |
|
||||
| +----------------+ +----------------+ |
|
||||
| |
|
||||
+----------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user