From fe0f7ebb9546896a026f52afcecd0b175bb3afc4 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sat, 7 Mar 2015 19:23:40 +0000 Subject: [PATCH] Add complex showcase sm sample --- build.gradle | 5 + .../reference/asciidoc/images/statechart2.png | Bin 0 -> 17099 bytes docs/src/reference/asciidoc/sm-examples.adoc | 36 ++++ settings.gradle | 1 + spring-statemachine-samples/build.gradle | 3 + .../showcase/.gitignore | 19 +++ .../main/java/demo/showcase/Application.java | 154 ++++++++++++++++++ .../demo/showcase/StateMachineCommands.java | 20 +++ .../META-INF/spring/spring-shell-plugin.xml | 8 + .../src/main/resources/statechartmodel.txt | 33 ++++ .../java/demo/showcase/ShowcaseTests.java | 41 +++++ 11 files changed, 320 insertions(+) create mode 100644 docs/src/reference/asciidoc/images/statechart2.png create mode 100644 spring-statemachine-samples/showcase/.gitignore create mode 100644 spring-statemachine-samples/showcase/src/main/java/demo/showcase/Application.java create mode 100644 spring-statemachine-samples/showcase/src/main/java/demo/showcase/StateMachineCommands.java create mode 100644 spring-statemachine-samples/showcase/src/main/resources/META-INF/spring/spring-shell-plugin.xml create mode 100644 spring-statemachine-samples/showcase/src/main/resources/statechartmodel.txt create mode 100644 spring-statemachine-samples/showcase/src/test/java/demo/showcase/ShowcaseTests.java diff --git a/build.gradle b/build.gradle index 86c3f855..16ad87ad 100644 --- a/build.gradle +++ b/build.gradle @@ -115,6 +115,10 @@ configure(sampleProjects()) { apply plugin: 'spring-boot' dependencies { compile project(":spring-statemachine-samples-common") + testCompile "org.springframework:spring-test:$springVersion" + testCompile "org.hamcrest:hamcrest-core:$hamcrestVersion" + testCompile "org.hamcrest:hamcrest-library:$hamcrestVersion" + testCompile "junit:junit:$junitVersion" } } @@ -176,6 +180,7 @@ configure(rootProject) { from 'spring-statemachine-core/src/test/java/org/springframework/statemachine/docs' from 'spring-statemachine-samples/src/main/java/' from 'spring-statemachine-samples/turnstile/src/main/java/' + from 'spring-statemachine-samples/showcase/src/main/java/' include '**/*.java' into 'docs/src/reference/asciidoc/samples' } diff --git a/docs/src/reference/asciidoc/images/statechart2.png b/docs/src/reference/asciidoc/images/statechart2.png new file mode 100644 index 0000000000000000000000000000000000000000..76f06e4403af70f45896489f4884be788931d2ea GIT binary patch literal 17099 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

_d)xxboY{TuiV@=z++ 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Π_>53Z1sF~ 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 literal 0 HcmV?d00001 diff --git a/docs/src/reference/asciidoc/sm-examples.adoc b/docs/src/reference/asciidoc/sm-examples.adoc index 831e7681..ca8c1078 100644 --- a/docs/src/reference/asciidoc/sm-examples.adoc +++ b/docs/src/reference/asciidoc/sm-examples.adoc @@ -75,3 +75,39 @@ State changed to LOCKED Event PUSH send ---- +== Showcase + +Showcase is a complex state machine showing all possible transition +topologies up to four levels of state nesting. + +image::images/statechart2.png[] + +.States +[source,java,indent=0] +---- +include::samples/demo/showcase/Application.java[tags=snippetB] +---- + +.Events +[source,java,indent=0] +---- +include::samples/demo/showcase/Application.java[tags=snippetC] +---- + +.Configuration +[source,java,indent=0] +---- +include::samples/demo/showcase/Application.java[tags=snippetA] +---- + +.Guard +[source,java,indent=0] +---- +include::samples/demo/showcase/Application.java[tags=snippetD] +---- + +.Action +[source,java,indent=0] +---- +include::samples/demo/showcase/Application.java[tags=snippetE] +---- diff --git a/settings.gradle b/settings.gradle index 009551c7..0ebfe7cb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,6 +4,7 @@ include 'spring-statemachine-core' include 'spring-statemachine-samples' include 'spring-statemachine-samples:turnstile' +include 'spring-statemachine-samples:showcase' rootProject.children.find { if (it.name == 'spring-statemachine-samples') { diff --git a/spring-statemachine-samples/build.gradle b/spring-statemachine-samples/build.gradle index f7902797..9877be75 100644 --- a/spring-statemachine-samples/build.gradle +++ b/spring-statemachine-samples/build.gradle @@ -4,3 +4,6 @@ project('spring-statemachine-samples-turnstile') { description = 'Spring State Machine Turnstile Sample' } +project('spring-statemachine-samples-showcase') { + description = 'Spring State Machine Showcase Sample' +} diff --git a/spring-statemachine-samples/showcase/.gitignore b/spring-statemachine-samples/showcase/.gitignore new file mode 100644 index 00000000..70e6e4b8 --- /dev/null +++ b/spring-statemachine-samples/showcase/.gitignore @@ -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 diff --git a/spring-statemachine-samples/showcase/src/main/java/demo/showcase/Application.java b/spring-statemachine-samples/showcase/src/main/java/demo/showcase/Application.java new file mode 100644 index 00000000..86d24b07 --- /dev/null +++ b/spring-statemachine-samples/showcase/src/main/java/demo/showcase/Application.java @@ -0,0 +1,154 @@ +package demo.showcase; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.shell.Bootstrap; +import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.action.Action; +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; +import org.springframework.statemachine.guard.Guard; + +@Configuration +public class Application { + +//tag::snippetA[] + @Configuration + @EnableStateMachine + static class StateMachineConfig + extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) + throws Exception { + states + .withStates() + .initial(States.S0) + .state(States.S0) + .and() + .withStates() + .parent(States.S0) + .initial(States.S1) + .state(States.S1) + .and() + .withStates() + .parent(States.S1) + .initial(States.S11) + .state(States.S11) + .and() + .withStates() + .parent(States.S0) + .state(States.S2) + .and() + .withStates() + .parent(States.S2) + .initial(States.S21) + .state(States.S21) + .and() + .withStates() + .parent(States.S21) + .initial(States.S211) + .state(States.S211); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) + throws Exception { + transitions + .withExternal() + .source(States.S1).target(States.S1).event(Events.A) + .action(fooAction()) + .and() + .withExternal() + .source(States.S1).target(States.S11).event(Events.B) + .and() + .withExternal() + .source(States.S21).target(States.S211).event(Events.B) + .and() + .withExternal() + .source(States.S1).target(States.S2).event(Events.C) + .and() + .withExternal() + .source(States.S2).target(States.S1).event(Events.C) + .and() + .withExternal() + .source(States.S1).target(States.S0).event(Events.D) + .and() + .withExternal() + .source(States.S211).target(States.S21).event(Events.D) + .and() + .withExternal() + .source(States.S0).target(States.S211).event(Events.E) + .and() + .withExternal() + .source(States.S1).target(States.S211).event(Events.F) + .and() + .withExternal() + .source(States.S2).target(States.S11).event(Events.F) + .and() + .withExternal() + .source(States.S11).target(States.S211).event(Events.G) + .and() + .withExternal() + .source(States.S211).target(States.S0).event(Events.G) + .and() + .withExternal() + .source(States.S21).target(States.S21).event(Events.H) + .guard(fooGuard()); + + } + + @Bean + public FooGuard fooGuard() { + return new FooGuard(); + } + + @Bean + public FooAction fooAction() { + return new FooAction(); + } + + } +//end::snippetA[] + +//tag::snippetB[] + public static enum States { + S0, S1, S11, S2, S21, S211 + } +//end::snippetB[] + +//tag::snippetC[] + public static enum Events { + A, B, C, D, E, F, G, H + } +//end::snippetC[] + +// tag::snippetD[] + private static class FooAction implements Action { + + @Override + public void execute(StateContext context) { + context.getExtendedState().getVariables().put("foo", 1); + } + } + +// end::snippetD[] + +// tag::snippetE[] + private static class FooGuard implements Guard { + + @Override + public boolean evaluate(StateContext context) { + Object foo = context.getExtendedState().getVariables().get("foo"); + return !(foo == null || !foo.equals(1)); + } + } +// end::snippetE[] + + public static void main(String[] args) throws Exception { + Bootstrap.main(args); + } + +} diff --git a/spring-statemachine-samples/showcase/src/main/java/demo/showcase/StateMachineCommands.java b/spring-statemachine-samples/showcase/src/main/java/demo/showcase/StateMachineCommands.java new file mode 100644 index 00000000..f8adb7fe --- /dev/null +++ b/spring-statemachine-samples/showcase/src/main/java/demo/showcase/StateMachineCommands.java @@ -0,0 +1,20 @@ +package demo.showcase; + +import org.springframework.shell.core.annotation.CliCommand; +import org.springframework.shell.core.annotation.CliOption; +import org.springframework.stereotype.Component; + +import demo.AbstractStateMachineCommands; +import demo.showcase.Application.Events; +import demo.showcase.Application.States; + +@Component +public class StateMachineCommands extends AbstractStateMachineCommands { + + @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"; + } + +} \ No newline at end of file diff --git a/spring-statemachine-samples/showcase/src/main/resources/META-INF/spring/spring-shell-plugin.xml b/spring-statemachine-samples/showcase/src/main/resources/META-INF/spring/spring-shell-plugin.xml new file mode 100644 index 00000000..1fc09f1f --- /dev/null +++ b/spring-statemachine-samples/showcase/src/main/resources/META-INF/spring/spring-shell-plugin.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/spring-statemachine-samples/showcase/src/main/resources/statechartmodel.txt b/spring-statemachine-samples/showcase/src/main/resources/statechartmodel.txt new file mode 100644 index 00000000..c0da1297 --- /dev/null +++ b/spring-statemachine-samples/showcase/src/main/resources/statechartmodel.txt @@ -0,0 +1,33 @@ ++---------------------------------------------------------------------------------------------+ +| S0 | ++---------------------------------------------------------------------------------------------+ +| entry/ | +| exit/ | +| +-------------------------+ +--------------------------------------------+ | +| *-->| S1 | | S2 | | +| +-------------------------+ C +--------------------------------------------+ | +| | entry/ | | entry/ H | | +| D | exit/ |----->| exit/ +-------------------+ | | +|<<---------| | | | H[foo.equals(1)]; | | | +| | +---------------+ | C | +------------------------------+ | | | +| | *-->| S11 | |<-----| *-->| S21 |<--+ | | +| | +---------------+ | | +------------------------------+ | | +| +--| | entry/ | | F | | entry/ | | | +| A| | | exit/ |<---------| | exit/ | | | +| +->| | | | | | +--------------+ | | | +| A[foo 1]; | B | | | | | *-->| s211 | | | | +| |---->| | | | F | +--------------+ | | | +| | | | |-------------------->| entry/ | | G | | +| | | | | | G | | exit/ |----------------->| +| | | |------------------------>| | | | | +| | | | | | | B | | | E | | +| | | | | | |------>| |<-----------------| +| | | | | | | | | | | | +| | | | | | | D | | | | | +| | | | | | |<------| | | | | +| | | | | | | +--------------+ | | | +| | +---------------+ | | +------------------------------+ | | +| | | | | | +| +-------------------------+ +--------------------------------------------+ | +| | ++---------------------------------------------------------------------------------------------+ diff --git a/spring-statemachine-samples/showcase/src/test/java/demo/showcase/ShowcaseTests.java b/spring-statemachine-samples/showcase/src/test/java/demo/showcase/ShowcaseTests.java new file mode 100644 index 00000000..e2a53907 --- /dev/null +++ b/spring-statemachine-samples/showcase/src/test/java/demo/showcase/ShowcaseTests.java @@ -0,0 +1,41 @@ +package demo.showcase; + +import org.junit.After; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.EnumStateMachine; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.StateMachineSystemConstants; + +import demo.CommonConfiguration; +import demo.showcase.Application.Events; +import demo.showcase.Application.States; + +public class ShowcaseTests { + + private AnnotationConfigApplicationContext context; + + @SuppressWarnings("resource") + @Test + public void testApplication() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(CommonConfiguration.class, Application.class); + context.refresh(); + @SuppressWarnings("unchecked") + StateMachine machine = context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, EnumStateMachine.class); + + machine.start(); + + machine.sendEvent(Events.A); + + } + + @After + public void clean() { + if (context != null) { + context.close(); + context = null; + } + } + +}