Add complex showcase sm sample

This commit is contained in:
Janne Valkealahti
2015-03-07 19:23:40 +00:00
parent 5bdf642005
commit fe0f7ebb95
11 changed files with 320 additions and 0 deletions

View File

@@ -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'
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -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]
----

View File

@@ -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') {

View File

@@ -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'
}

View 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

View File

@@ -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<States, Events> {
@Override
public void configure(StateMachineStateConfigurer<States, Events> 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<States, Events> 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<States, Events> {
@Override
public void execute(StateContext<States, Events> context) {
context.getExtendedState().getVariables().put("foo", 1);
}
}
// end::snippetD[]
// tag::snippetE[]
private static class FooGuard implements Guard<States, Events> {
@Override
public boolean evaluate(StateContext<States, Events> 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);
}
}

View File

@@ -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<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";
}
}

View File

@@ -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>

View File

@@ -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 | | | | |
| | | | | | |<------| | | | |
| | | | | | | +--------------+ | | |
| | +---------------+ | | +------------------------------+ | |
| | | | | |
| +-------------------------+ +--------------------------------------------+ |
| |
+---------------------------------------------------------------------------------------------+

View File

@@ -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<States,Events> 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;
}
}
}