From 61ec8723df1433ca1cdc9676c4b448dc0307bb07 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Fri, 29 May 2015 10:59:47 +0100 Subject: [PATCH] Updates to docs --- build.gradle | 1 + docs/src/reference/asciidoc/appendix.adoc | 65 ++++++ .../reference/asciidoc/images/statechart5.png | Bin 0 -> 14574 bytes .../reference/asciidoc/images/statechart6.png | Bin 0 -> 10832 bytes docs/src/reference/asciidoc/sm-examples.adoc | 180 ++++++++++++++ docs/src/reference/asciidoc/sm.adoc | 110 +++++++++ .../docs/DocsConfigurationSampleTests.java | 220 ++++++++++++++++++ .../statemachine/docs/States2.java | 9 + .../statemachine/docs/States3.java | 8 + .../src/main/java/demo/tasks/Application.java | 14 +- .../main/java/demo/washer/Application.java | 20 +- .../src/main/resources/statechartmodel.txt | 56 ++--- 12 files changed, 644 insertions(+), 39 deletions(-) create mode 100644 docs/src/reference/asciidoc/images/statechart5.png create mode 100644 docs/src/reference/asciidoc/images/statechart6.png create mode 100644 spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/States2.java create mode 100644 spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/States3.java diff --git a/build.gradle b/build.gradle index 6af1e33e..5a01c1a4 100644 --- a/build.gradle +++ b/build.gradle @@ -181,6 +181,7 @@ configure(rootProject) { task copyDocsSamples(type: Copy) { from 'spring-statemachine-core/src/test/java/org/springframework/statemachine/docs' from 'spring-statemachine-samples/src/main/java/' + from 'spring-statemachine-samples/washer/src/main/java/' from 'spring-statemachine-samples/tasks/src/main/java/' from 'spring-statemachine-samples/turnstile/src/main/java/' from 'spring-statemachine-samples/showcase/src/main/java/' diff --git a/docs/src/reference/asciidoc/appendix.adoc b/docs/src/reference/asciidoc/appendix.adoc index 96e07c4f..9897e098 100644 --- a/docs/src/reference/asciidoc/appendix.adoc +++ b/docs/src/reference/asciidoc/appendix.adoc @@ -15,6 +15,16 @@ material in this reference documentation. include::samples/States.java[tags=snippetA] ---- +[source,java,indent=0] +---- +include::samples/States2.java[tags=snippetA] +---- + +[source,java,indent=0] +---- +include::samples/States3.java[tags=snippetA] +---- + [source,java,indent=0] ---- include::samples/Events.java[tags=snippetA] @@ -86,6 +96,22 @@ 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. +*History State*:: +A pseudo state which allows a state machine to remember its last +active state. Two types of history state exists, _shallow_ which only +remember top level state and _deep_ which remembers active states in a +sub-machines. + +*Choice State*:: +A pseudo state which allows to make a transition choice based of i.e. +event headers or extended state variables. + +*Fork State*:: +A pseudo state which gives a controlled entry into a regions. + +*Join State*:: +A pseudo state which gives a controlled exit from a regions. + *Region*:: A region is an orthogonal part of either a composite state or a state machine. It contains states and transitions. @@ -124,6 +150,45 @@ flags, nested if/else/break clauses or other impractical logic you simply rely on state, state variables or other interaction with a state machine. +==== Pseudo States +PseudoState is a special type of state which usually introduces more +higher level logic into a state machine by either giving a state a +special meaning like initial state. State machine can then internally +react to these states by doing various actions available in UML state +machine concepts. + +===== Initial +Initial state is always needed for every single state machine whether +you have a simple one level state machine or more complex state +machine composed with submachines or regions. Initial state simple +defines where state machine should go when it starts and without it +state machine is ill-formed. + +===== End +Terminate state which is also called as end state will indicate that a +particular state machine has reached its final state. Effectively this +mean that a state machine will no longer process any events and will +not transit to any other state. However in a case of submachines are +regions, state machine is able to restart from its terminal state. + +===== Choice +Choice can be used to choose a transition conditionally. + +===== History +History state can be used to remember a last active state +configuration. After state machine has been exited, history state can +be used to restore previous knows configuration. There are two types +of history states available, _SHALLOW_ only remember active state of a +state machine itself while _DEEP_ also remembers nested states. + +===== Fork +Fork can be used to do an explicit entry into one or more regions. + +===== Join +Join is used to merge several transitions together originating from +different regions. It it generally used to wait and block for +participating regions to get into its join target states. + ==== Guard Conditions Guard conditions are expressions which evaluates either to *TRUE* or *FALSE* based on extended state variables and event parameters. Guards diff --git a/docs/src/reference/asciidoc/images/statechart5.png b/docs/src/reference/asciidoc/images/statechart5.png new file mode 100644 index 0000000000000000000000000000000000000000..4a02b9c0dbdbe870dd7afecb1ee6a7712951490a GIT binary patch literal 14574 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 literal 0 HcmV?d00001 diff --git a/docs/src/reference/asciidoc/images/statechart6.png b/docs/src/reference/asciidoc/images/statechart6.png new file mode 100644 index 0000000000000000000000000000000000000000..cea601c83e6a37d0dd2e305eae0a2d9df194b94e GIT binary patch literal 10832 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 start +State machine started +Entry state READY + +sm>tasks run +Entry state TASKS +run task on T1 +run task on T2 +run task on T3 +run task on T1 done +run task on T2 done +run task on T3 done +Entry state T1 +Entry state T3 +Entry state T2 +Entry state T1E +Entry state T2E +Entry state T3E +Exit state TASKS +Entry state JOIN +Exit state JOIN +Entry state READY + +sm> +---- + +== Washer + +Washer is a sample demonstrating a use of a history state to recover a +running state configuration with a simulated power off situation. + +Anyone ever used a washing machine knows that if you can somehow pause +the program it will continue from a same state when lid is closed. +This kind of behaviour can be implemented in a state machine by using +a history pseudo state. + +image::images/statechart6.png[width=500] + +.States +[source,java,indent=0] +---- +include::samples/demo/washer/Application.java[tags=snippetB] +---- + +.Events +[source,java,indent=0] +---- +include::samples/demo/washer/Application.java[tags=snippetC] +---- + +.Configuration - states +[source,java,indent=0] +---- +include::samples/demo/washer/Application.java[tags=snippetAA] +---- + +.Configuration - transitions +[source,java,indent=0] +---- +include::samples/demo/washer/Application.java[tags=snippetAB] +---- + +Lets see an example how this state machine actually works. +[source,text] +---- +sm>sm start +Entry state RUNNING +Entry state WASHING +State machine started + +sm>sm event RINSE +Exit state WASHING +Entry state RINSING +Event RINSE send + +sm>sm event DRY +Exit state RINSING +Entry state DRYING +Event DRY send + +sm>sm event CUTPOWER +Exit state DRYING +Exit state RUNNING +Entry state POWEROFF +Event CUTPOWER send + +sm>sm event RESTOREPOWER +Exit state POWEROFF +Entry state RUNNING +Entry state WASHING +Entry state DRYING +Event RESTOREPOWER send +---- + +What happened in above run: + +* State machine is started which causes machine to get initialized. +* We go to RINSING state. +* We go to DRYING state. +* We cut power and go to POWEROFF state. +* State is restored via HISTORY state which takes state machine back + to its previous known state. + diff --git a/docs/src/reference/asciidoc/sm.adoc b/docs/src/reference/asciidoc/sm.adoc index 83ec552c..976e0115 100644 --- a/docs/src/reference/asciidoc/sm.adoc +++ b/docs/src/reference/asciidoc/sm.adoc @@ -22,6 +22,15 @@ Statemachine is configured and how it leverages Spring's lightweight IoC containers to simplify the application internals to make it more manageable. +[NOTE] +==== +Configuration examples in this section are not feature complete, i.e. +you always need to have definitions of both states and transitions, +otherwise state machine configuration would be ill-formed. We have +simply made code snippets less verbose by leaving other needed parts +away. +==== + === 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 @@ -43,6 +52,20 @@ particular states are sub-states of some other state. include::samples/DocsConfigurationSampleTests.java[tags=snippetB] ---- +=== Configuring Regions + +There are no special configuration methods to mark a collection of +states to be part of a orthogonal state. To put it simple, orthogonal +state is created when same hierarchical state machine has multiple set +of states each having a initial state. Because a individual state +machine can only have one initial state, multiple initial states mush +mean that a specific state mush have multiple independent regions. + +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests.java[tags=snippetP] +---- + === Configuring Transitions We support three different types of transitions, `external`, `internal` and `local`. Transitions are either triggered by a signal @@ -80,6 +103,93 @@ Actions can be defined with various steps within a state transitions. include::samples/DocsConfigurationSampleTests.java[tags=snippetE] ---- +=== Configuring Pseudo States + +_Pseudo state_ configuration is usually done by configuring states and +transitions. Pseudo states are automatically added to state machine as +states. + +==== Initial State +Simply mark a particular state as initial state by using `initial()` +method. There are two methods where one takes extra argument to define +an initial action. This initial action is good for example initialize +extended state variables. + +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests.java[tags=snippetQ] +---- + +==== Terminate State +Simply mark a particular state as end state by using `end()` method. +This can be done max one time per individual sub-machine or region. + +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests.java[tags=snippetA] +---- + +==== History State +History state can be defined once for each individual state machine. +You need to choose its state identifier and `History.SHALLOW` or +`History.DEEP` respectively. + +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests.java[tags=snippetR] +---- + +==== Choice State +Choice needs to be defined in both states and transitions to work +properly. Mark particular state as choice state by using `choice()` +method. This state needs to match source state when transition is +configured for this choice. + +Transition is configured using `withChoice()` where you define source +state and `first/then/last` structure which is equivalent to normal +`if/elseif/else`. With `first` and `then` you can specify a guard just +like you'd use a condition with `if/elseif` clauses. + +Transition needs to be able to exist so make sure `last` is used. +Otherwise configuration is ill-formed. + +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests.java[tags=snippetS] +---- + +==== Fork State +Fork needs to be defined in both states and transitions to work +properly. Mark particular state as choice state by using `fork()` +method. This state needs to match source state when transition is +configured for this fork. + +Target state needs to be a super state or immediate states in +regions. Using a super state as target will take all regions into +initial states. Targeting individual state give more controlled entry +into regions. + +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests.java[tags=snippetT] +---- + +==== Join State +Join needs to be defined in both states and transitions to work +properly. Mark particular state as choice state by using `join()` +method. This state doesn't need to match either source states or +target state in a transition configuretion. + +Select one target state where transition goes when all source states +has been joined. If you use state hosting regions as source, end +states of a regions are used as joins. Otherwise you can pick any +states from a regions. + +[source,java,indent=0] +---- +include::samples/DocsConfigurationSampleTests.java[tags=snippetU] +---- + [[sm-factories]] == State Machine Factories There are use cases when state machine needs to be created dynamically diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java index b91beed0..0b67911f 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/DocsConfigurationSampleTests.java @@ -39,6 +39,7 @@ import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter import org.springframework.statemachine.config.StateMachineFactory; import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.config.configurers.StateConfigurer.History; import org.springframework.statemachine.event.StateMachineEvent; import org.springframework.statemachine.guard.Guard; import org.springframework.statemachine.listener.StateMachineListenerAdapter; @@ -354,4 +355,223 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests { } +// tag::snippetP[] + @Configuration + @EnableStateMachine + public static class Config10 + extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) + throws Exception { + states + .withStates() + .initial(States2.S1) + .state(States2.S2) + .and() + .withStates() + .parent(States2.S2) + .initial(States2.S2I) + .state(States2.S21) + .end(States2.S2F) + .and() + .withStates() + .parent(States2.S2) + .initial(States2.S3I) + .state(States2.S31) + .end(States2.S3F); + } + + } +// end::snippetP[] + +// tag::snippetQ[] + @Configuration + @EnableStateMachine + public static class Config11 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) + throws Exception { + states + .withStates() + .initial(States.S1, initialAction()) + .end(States.SF) + .states(EnumSet.allOf(States.class)); + } + + @Bean + public Action initialAction() { + return new Action() { + + @Override + public void execute(StateContext context) { + // do something initially + } + }; + } + + } +// end::snippetQ[] + +// tag::snippetR[] + @Configuration + @EnableStateMachine + public static class Config12 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) + throws Exception { + states + .withStates() + .initial(States3.S1) + .state(States3.S2) + .and() + .withStates() + .parent(States3.S2) + .initial(States3.S2I) + .state(States3.S21) + .state(States3.S22) + .history(States3.SH, History.SHALLOW); + } + + } +// end::snippetR[] + +// tag::snippetS[] + @Configuration + @EnableStateMachine + public static class Config13 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) + throws Exception { + states + .withStates() + .initial(States.SI) + .choice(States.S1) + .end(States.SF) + .states(EnumSet.allOf(States.class)); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) + throws Exception { + transitions + .withChoice() + .source(States.S1) + .first(States.S2, s2Guard()) + .then(States.S3, s3Guard()) + .last(States.S4); + } + + @Bean + public Guard s2Guard() { + return new Guard() { + + @Override + public boolean evaluate(StateContext context) { + return false; + } + }; + } + + @Bean + public Guard s3Guard() { + return new Guard() { + + @Override + public boolean evaluate(StateContext context) { + return true; + } + }; + } + + } +// end::snippetS[] + +// tag::snippetT[] + @Configuration + @EnableStateMachine + public static class Config14 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) + throws Exception { + states + .withStates() + .initial(States2.S1) + .fork(States2.S2) + .state(States2.S3) + .and() + .withStates() + .parent(States2.S3) + .initial(States2.S2I) + .state(States2.S21) + .state(States2.S22) + .end(States2.S2F) + .and() + .withStates() + .parent(States2.S3) + .initial(States2.S3I) + .state(States2.S31) + .state(States2.S32) + .end(States2.S3F); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) + throws Exception { + transitions + .withFork() + .source(States2.S2) + .target(States2.S22) + .target(States2.S32); + } + + } +// end::snippetT[] + +// tag::snippetU[] + @Configuration + @EnableStateMachine + public static class Config15 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) + throws Exception { + states + .withStates() + .initial(States2.S1) + .state(States2.S3) + .join(States2.S4) + .and() + .withStates() + .parent(States2.S3) + .initial(States2.S2I) + .state(States2.S21) + .state(States2.S22) + .end(States2.S2F) + .and() + .withStates() + .parent(States2.S3) + .initial(States2.S3I) + .state(States2.S31) + .state(States2.S32) + .end(States2.S3F); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) + throws Exception { + transitions + .withJoin() + .source(States2.S2F) + .source(States2.S3F) + .target(States2.S5); + } + + } +// end::snippetU[] + } diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/States2.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/States2.java new file mode 100644 index 00000000..68df59d2 --- /dev/null +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/States2.java @@ -0,0 +1,9 @@ +package org.springframework.statemachine.docs; + +//tag::snippetA[] +public enum States2 { + S1,S2,S3,S4,S5, + S2I,S21,S22,S2F, + S3I,S31,S32,S3F +} +//end::snippetA[] diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/States3.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/States3.java new file mode 100644 index 00000000..af5d2b21 --- /dev/null +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/docs/States3.java @@ -0,0 +1,8 @@ +package org.springframework.statemachine.docs; + +//tag::snippetA[] +public enum States3 { + S1,S2,SH, + S2I,S21,S22,S2F +} +//end::snippetA[] diff --git a/spring-statemachine-samples/tasks/src/main/java/demo/tasks/Application.java b/spring-statemachine-samples/tasks/src/main/java/demo/tasks/Application.java index 1b45b463..bb3f688e 100644 --- a/spring-statemachine-samples/tasks/src/main/java/demo/tasks/Application.java +++ b/spring-statemachine-samples/tasks/src/main/java/demo/tasks/Application.java @@ -23,12 +23,12 @@ import org.springframework.statemachine.guard.Guard; @Configuration public class Application { -//tag::snippetA[] @Configuration @EnableStateMachine static class StateMachineConfig extends EnumStateMachineConfigurerAdapter { +//tag::snippetAA[] @Override public void configure(StateMachineStateConfigurer states) throws Exception { @@ -62,7 +62,9 @@ public class Application { .state(States.AUTOMATIC, automaticAction(), null) .state(States.MANUAL); } +//end::snippetAA[] +//tag::snippetAB[] @Override public void configure(StateMachineTransitionConfigurer transitions) throws Exception { @@ -108,7 +110,9 @@ public class Application { .state(States.ERROR) .event(Events.FIX); } +//end::snippetAB[] +//tag::snippetAC[] @Bean public Guard tasksChoiceGuard() { return new Guard() { @@ -121,7 +125,9 @@ public class Application { } }; } +//end::snippetAC[] +//tag::snippetAD[] @Bean public Action automaticAction() { return new Action() { @@ -152,21 +158,25 @@ public class Application { } }; } +//end::snippetAD[] +//tag::snippetAE[] @Bean public Tasks tasks() { return new Tasks(); } +//end::snippetAE[] +//tag::snippetAF[] @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(5); return taskExecutor; } +//end::snippetAF[] } -//end::snippetA[] //tag::snippetB[] public static enum States { diff --git a/spring-statemachine-samples/washer/src/main/java/demo/washer/Application.java b/spring-statemachine-samples/washer/src/main/java/demo/washer/Application.java index 05f1ac87..b9a3cf71 100644 --- a/spring-statemachine-samples/washer/src/main/java/demo/washer/Application.java +++ b/spring-statemachine-samples/washer/src/main/java/demo/washer/Application.java @@ -41,24 +41,24 @@ public class Application { throws Exception { transitions .withExternal() - .source(States.WASHING) - .target(States.RINSING) + .source(States.WASHING).target(States.RINSING) .event(Events.RINSE) .and() .withExternal() - .source(States.RINSING) - .target(States.DRYING) + .source(States.RINSING).target(States.DRYING) .event(Events.DRY) .and() .withExternal() - .source(States.RUNNING) - .target(States.POWEROFF) + .source(States.RUNNING) .target(States.POWEROFF) .event(Events.CUTPOWER) .and() .withExternal() - .source(States.POWEROFF) - .target(States.HISTORY) - .event(Events.RESTOREPOWER); + .source(States.POWEROFF).target(States.HISTORY) + .event(Events.RESTOREPOWER) + .and() + .withExternal() + .source(States.RUNNING).target(States.END) + .event(Events.STOP); } //end::snippetAB[] @@ -74,7 +74,7 @@ public class Application { //tag::snippetC[] public static enum Events { - RINSE, DRY, + RINSE, DRY, STOP, RESTOREPOWER, CUTPOWER } //end::snippetC[] diff --git a/spring-statemachine-samples/washer/src/main/resources/statechartmodel.txt b/spring-statemachine-samples/washer/src/main/resources/statechartmodel.txt index 579812e5..b413cac9 100644 --- a/spring-statemachine-samples/washer/src/main/resources/statechartmodel.txt +++ b/spring-statemachine-samples/washer/src/main/resources/statechartmodel.txt @@ -1,27 +1,29 @@ -+----------------------------------------------------------------------------------+ -| | -+----------------------------------------------------------------------------------+ -| | -| +--------------------------------------------------------------------+ | -| *-->| RUNNING |-->X | -| +--------------------------------------------------------------------+ | -| | | | -| | +-------------+ +-------------+ +-------------+ | | -| | *-->| WASHING | RINSE | RINSING | DRY | DRYING | | | -| | | |------>| |------>| | | | -| | | | | | | | | | -| | +-------------+ +-------------+ +-------------+ | | -| | | | -| | H | | -| | ^ | | -| +------------|-------------------------------------------------------+ | -| | | | -| |RESTOREPOWER |CUTPOWER | -| | | | -| +-------------+ | | -| | POWEROFF | | | -| | |<----------+ | -| | | | -| +-------------+ | -| | -+----------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------+ +| | ++--------------------------------------------------------------------------------------+ +| | +| +--------------------------------------------------------------------+ STOP | +| *-->| RUNNING |------>X | +| +--------------------------------------------------------------------+ | +| | | | +| | +-------------+ +-------------+ +-------------+ | | +| | *-->| WASHING | RINSE | RINSING | DRY | DRYING | | | +| | | |------>| |------>| | | | +| | | | | | | | | | +| | +-------------+ +-------------+ +-------------+ | | +| | | | +| | +-------+ | | +| | |HISTORY| | | +| | +-------+ | | +| | ^ | | +| +------------|-------------------------------------------------------+ | +| | | | +| |RESTOREPOWER |CUTPOWER | +| | | | +| +-------------+ | | +| | POWEROFF | | | +| | |<----------+ | +| | | | +| +-------------+ | +| | ++--------------------------------------------------------------------------------------+