Add new tasks sample

This commit is contained in:
Janne Valkealahti
2015-05-17 16:04:52 +01:00
parent 2a31254b91
commit cc4794d014
12 changed files with 602 additions and 0 deletions

View File

@@ -0,0 +1,193 @@
package demo.tasks;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
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.annotation.OnTransition;
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.READY)
.fork(States.FORK)
.state(States.TASKS)
.join(States.JOIN)
.choice(States.CHOICE)
.state(States.ERROR)
.and()
.withStates()
.parent(States.TASKS)
.initial(States.T1)
.end(States.T1E)
.and()
.withStates()
.parent(States.TASKS)
.initial(States.T2)
.end(States.T2E)
.and()
.withStates()
.parent(States.TASKS)
.initial(States.T3)
.end(States.T3E)
.and()
.withStates()
.parent(States.ERROR)
.initial(States.AUTOMATIC)
.state(States.AUTOMATIC, automaticAction(), null)
.state(States.MANUAL);
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
throws Exception {
transitions
.withExternal()
.source(States.READY).target(States.FORK)
.event(Events.RUN)
.and()
.withFork()
.source(States.FORK).target(States.TASKS)
.and()
.withExternal()
.source(States.T1).target(States.T1E)
.and()
.withExternal()
.source(States.T2).target(States.T2E)
.and()
.withExternal()
.source(States.T3).target(States.T3E)
.and()
.withJoin()
.source(States.TASKS).target(States.JOIN)
.and()
.withExternal()
.source(States.JOIN).target(States.CHOICE)
.and()
.withChoice()
.source(States.CHOICE)
.first(States.ERROR, tasksChoiceGuard())
.last(States.READY)
.and()
.withExternal()
.source(States.ERROR).target(States.READY)
.event(Events.CONTINUE)
.and()
.withExternal()
.source(States.AUTOMATIC).target(States.MANUAL)
.event(Events.FALLBACK)
.and()
.withInternal()
.source(States.MANUAL)
.action(fixAction())
.state(States.ERROR)
.event(Events.FIX);
}
@Bean
public Guard<States, Events> tasksChoiceGuard() {
return new Guard<States, Events>() {
@Override
public boolean evaluate(StateContext<States, Events> context) {
Map<Object, Object> variables = context.getExtendedState().getVariables();
return !(variables.get("T1").equals(true) && variables.get("T2").equals(true) && variables
.get("T3").equals(true));
}
};
}
@Bean
public Action<States, Events> automaticAction() {
return new Action<States, Events>() {
@Override
public void execute(StateContext<States, Events> context) {
Map<Object, Object> variables = context.getExtendedState().getVariables();
if (variables.get("T1").equals(false)) {
variables.put("T1", true);
context.getStateMachine().sendEvent(Events.CONTINUE);
} else {
context.getStateMachine().sendEvent(Events.FALLBACK);
}
}
};
}
@Bean
public Action<States, Events> fixAction() {
return new Action<States, Events>() {
@Override
public void execute(StateContext<States, Events> context) {
Map<Object, Object> variables = context.getExtendedState().getVariables();
if (variables.get("T1").equals(true) && variables.get("T2").equals(true)
&& variables.get("T3").equals(true)) {
context.getStateMachine().sendEvent(Events.CONTINUE);
}
}
};
}
@Bean
public Tasks tasks() {
return new Tasks();
}
}
//end::snippetA[]
//tag::snippetB[]
public static enum States {
READY,
FORK, JOIN, CHOICE,
TASKS, T1, T1E, T2, T2E, T3, T3E,
ERROR, AUTOMATIC, MANUAL
}
//end::snippetB[]
//tag::snippetC[]
public static enum Events {
RUN, FALLBACK, CONTINUE, FIX;
}
//end::snippetC[]
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@OnTransition
public static @interface StatesOnTransition {
States[] source() default {};
States[] target() default {};
}
public static void main(String[] args) throws Exception {
Bootstrap.main(args);
}
}

View File

@@ -0,0 +1,20 @@
package demo.tasks;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.springframework.stereotype.Component;
import demo.AbstractStateMachineCommands;
import demo.tasks.Application.Events;
import demo.tasks.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,95 @@
package demo.tasks;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.ExtendedState;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.annotation.WithStateMachine;
import demo.tasks.Application.Events;
import demo.tasks.Application.States;
import demo.tasks.Application.StatesOnTransition;
@WithStateMachine
public class Tasks {
private final static Log log = LogFactory.getLog(Tasks.class);
@Autowired
private StateMachine<States, Events> stateMachine;
private final Map<String, Boolean> tasks = new HashMap<String, Boolean>();
public Tasks() {
tasks.put("T1", true);
tasks.put("T2", true);
tasks.put("T3", true);
}
public void run() {
stateMachine.sendEvent(Events.RUN);
}
public void cont() {
stateMachine.sendEvent(Events.CONTINUE);
}
public void fix(String task) {
if (tasks.containsKey(task)) {
tasks.put(task, true);
}
stateMachine.sendEvent(Events.FIX);
}
public void fail(String task) {
if (tasks.containsKey(task)) {
tasks.put(task, false);
}
}
@StatesOnTransition(target = States.T1)
public void taskT1(ExtendedState extendedState) {
log.info("run task on T1");
extendedState.getVariables().put("T1", tasks.get("T1"));
}
@StatesOnTransition(target = States.T2)
public void taskT2(ExtendedState extendedState) {
log.info("run task on T2");
extendedState.getVariables().put("T2", tasks.get("T2"));
}
@StatesOnTransition(target = States.T3)
public void taskT3(ExtendedState extendedState) {
log.info("run task on T3");
extendedState.getVariables().put("T3", tasks.get("T3"));
}
@StatesOnTransition(target = States.AUTOMATIC)
public void automaticFix(ExtendedState extendedState) {
Map<Object, Object> variables = extendedState.getVariables();
if (variables.get("T1").equals(false)) {
variables.put("T1", true);
tasks.put("T1", true);
}
}
@StatesOnTransition(target = States.MANUAL)
public void manualFix(ExtendedState extendedState) {
Map<Object, Object> variables = extendedState.getVariables();
if (variables.get("T2").equals(false)) {
variables.put("T2", true);
tasks.put("T2", true);
}
}
@Override
public String toString() {
return "Tasks " + tasks;
}
}

View File

@@ -0,0 +1,35 @@
package demo.tasks;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.springframework.stereotype.Component;
@Component
public class TasksCommands implements CommandMarker {
@Autowired
private Tasks tasks;
@CliCommand(value = "tasks run", help = "Run tasks")
public void run() {
tasks.run();
}
@CliCommand(value = "tasks list", help = "List tasks")
public String list() {
return tasks.toString();
}
@CliCommand(value = "tasks fix", help = "Fix task")
public void fix(@CliOption(key = {"", "task"}, help = "Task id") String task) {
tasks.fix(task);
}
@CliCommand(value = "tasks fail", help = "Fail task")
public void fail(@CliOption(key = {"", "task"}, help = "Task id") String task) {
tasks.fail(task);
}
}

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,40 @@
+----------------------------------------------------------------------------+
| SM |
+----------------------------------------------------------------------------+
| |
| +---------------------------+ |
| FORK | TASKS | JOIN |
| | +---------------------------+ | |
| +-------------+ RUN | | +------------+ | | |
| *-->| READY |----->|----->| *-->| T1 |-->X |---->|----+ |
| +-------------+ | | +------------+ | | | |
| ^ ^ | |===========================| | | |
| | | | +------------+ | | |
| | | | *-->| T2 |-->X | | |
| | | | +------------+ | | |
| | | |===========================| | |
| | | | +------------+ | | |
| | | | *-->| T3 |-->X | | |
| | | | +------------+ | | |
| | | +---------------------------+ | |
| | | | |
| | | [OK] +------------+ | |
| | +--------------------------| CHOICE |<----------------+ |
| | +------------+ |
| | | |
| | | [ERROR] |
| | v |
| | +-----------------------------------------------+ |
| | | ERROR | |
| | +-----------------------------------------------+ |
| | CONTINUE | +-------------+ FALLBACK +-------------+ | |
| +-------------| *-->| AUTOMATIC |--------->| MANUAL | | |
| | | | | | | |
| | | | | FIX | | |
| | | | | +-----+ | | |
| | | | | | | | | |
| | | | | | v | | |
| | +-------------+ +-------------+ | |
| +-----------------------------------------------+ |
| |
+----------------------------------------------------------------------------+