Driving a statemachine is done via transitions which are triggered by triggers. Currently supported triggers are EventTrigger and TimerTrigger.
EventTrigger is the most useful trigger because it allows user to directly interact with a state machine by sending events to it. These events are also called signals. Trigger is added to a transition simply by associating a state to it during a configuration.
@Autowired StateMachine<States, Events> stateMachine; void signalMachine() { stateMachine.sendEvent(Events.E1); Message<Events> message = MessageBuilder .withPayload(Events.E2) .setHeader("foo", "bar") .build(); stateMachine.sendEvent(message); }
In above example we send an event using two different ways. Firstly we
simply sent a type safe event using state machine api method
sendEvent(E event)
. Secondly we send event wrapped in a Spring
messaging Message using api method sendEvent(Message<E> message)
with a custom event headers. This allows user to add arbitrary extra
information with an event which is then visible to StateContext when
for example user is implementing actions.
Note | |
---|---|
Message headers are generally passed on until machine runs to
completion for a specific event. For example if an event is causing
transition into a state |
TimerTrigger is useful when something needs to be triggered
automatically without any user interaction. Trigger
is added to a
transition by associating a timer with it during a configuration.
Currently there are two types of timers supported, one which fires continously and one which fires once a source state is entered.
@Configuration @EnableStateMachine public class Config2 extends StateMachineConfigurerAdapter<String, String> { @Override public void configure(StateMachineStateConfigurer<String, String> states) throws Exception { states .withStates() .initial("S1") .state("S2") .state("S3"); } @Override public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception { transitions .withExternal() .source("S1").target("S2").event("E1") .and() .withExternal() .source("S1").target("S3").event("E2") .and() .withInternal() .source("S2") .action(timerAction()) .timer(1000) .and() .withInternal() .source("S3") .action(timerAction()) .timerOnce(1000); } @Bean public TimerAction timerAction() { return new TimerAction(); } } public class TimerAction implements Action<String, String> { @Override public void execute(StateContext<String, String> context) { // do something in every 1 sec } }
In above we have three states, S1
, S2
and S3
. We have a normal
external transition from S1
to S2
and from S1
to S3
with
events E1
and E2
respectively. Interesting parts are when we define
internal transitions for source states S2
and S3
.
For both transitions we associate Action
bean timerAction
where
source state S2
will use timer
and S3
will use timerOnce
.
Values given are with milliseconds which in these cases mean 1000ms
.
Once a state machine receive event E1
it does a transition
from S1
to S2
and timer kicks in. As long as state is kept in S2
TimerTrigger
executes and causes a transition associated with that
state which in this case is the internal transition which has the
timerAction
defined.
Once a state machine receive event E2
it does a transition
from S1
to S3
and timer kicks in. This timer is executed only once
after state is entered after a delay defined in a timer.
Note | |
---|---|
Behind a scenes timers are a simple triggers which may cause an
transition to happen. Defining a transition with a |
Tip | |
---|---|
Use |