Updates to docs

This commit is contained in:
Janne Valkealahti
2015-03-06 15:01:23 +00:00
parent de848cda20
commit ed81b1b578
24 changed files with 673 additions and 30 deletions

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@ build
.classpath
.project
*.iml
*.log
*.ipr
*.iws
metastore_db

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,19 @@
+----------------------------------------------------------------+
| SM |
+----------------------------------------------------------------+
| |
| +----------------+ +----------------+ |
| *-->| LOCKED | | UNLOCKED | |
| +----------------+ +----------------+ |
| +---| entry/ | | entry/ |---+ |
| | | exit/ | | exit/ | | |
| | | | | | | |
| PUSH| | |---COIN-->| | |COIN |
| | | | | | | |
| | | | | | | |
| | | |<--PUSH---| | | |
| +-->| | | |<--+ |
| | | | | |
| +----------------+ +----------------+ |
| |
+----------------------------------------------------------------+

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
package org.springframework.statemachine.docs;
//tag::snippetA[]
public enum MyEvents {
public enum Events {
E1,E2,E3,E4,EF
}
//end::snippetA[]

View File

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

View File

@@ -0,0 +1,6 @@
description = 'Spring State Machine Samples Common'
project('spring-statemachine-samples-turnstile') {
description = 'Spring State Machine Turnstile Sample'
}

View File

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

View File

@@ -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());
}
}
}
}

View File

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

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

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,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);
}
}

View File

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

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,19 @@
+----------------------------------------------------------------+
| SM |
+----------------------------------------------------------------+
| |
| +----------------+ +----------------+ |
| *-->| LOCKED | | UNLOCKED | |
| +----------------+ +----------------+ |
| +---| entry/ | | entry/ |---+ |
| | | exit/ | | exit/ | | |
| | | | | | | |
| PUSH| | |---COIN-->| | |COIN |
| | | | | | | |
| | | | | | | |
| | | |<--PUSH---| | | |
| +-->| | | |<--+ |
| | | | | |
| +----------------+ +----------------+ |
| |
+----------------------------------------------------------------+