Defining a state machine configuration with UI modeling is supported via Eclipse Papyrus framework.
From eclipse wizard create a new Papyrus Model with UML
Diagram
Language. In this example it’s named as simple-machine
. Then you’ve
given an option to choose various diagram kind’s and a StateMachine
Diagram
must be chosen.
We want to create a machine having two states, S1
and S2
where
S1
is initial state. Then event E1
is created to do a transition
from S1
to S2
. In papyrus a machine would then look like something
shown below.
Behind a scenes a raw uml file would look like.
<?xml version="1.0" encoding="UTF-8"?> <uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_AMP3IP8fEeW45bORGB4c_A" name="RootElement"> <packagedElement xmi:type="uml:StateMachine" xmi:id="_AMRFQP8fEeW45bORGB4c_A" name="StateMachine"> <region xmi:type="uml:Region" xmi:id="_AMRsUP8fEeW45bORGB4c_A" name="Region1"> <transition xmi:type="uml:Transition" xmi:id="_chgcgP8fEeW45bORGB4c_A" source="_EZrg4P8fEeW45bORGB4c_A" target="_FAvg4P8fEeW45bORGB4c_A"> <trigger xmi:type="uml:Trigger" xmi:id="_hs5jUP8fEeW45bORGB4c_A" event="_NeH84P8fEeW45bORGB4c_A"/> </transition> <transition xmi:type="uml:Transition" xmi:id="_egLIoP8fEeW45bORGB4c_A" source="_Fg0IEP8fEeW45bORGB4c_A" target="_EZrg4P8fEeW45bORGB4c_A"/> <subvertex xmi:type="uml:State" xmi:id="_EZrg4P8fEeW45bORGB4c_A" name="S1"/> <subvertex xmi:type="uml:State" xmi:id="_FAvg4P8fEeW45bORGB4c_A" name="S2"/> <subvertex xmi:type="uml:Pseudostate" xmi:id="_Fg0IEP8fEeW45bORGB4c_A"/> </region> </packagedElement> <packagedElement xmi:type="uml:Signal" xmi:id="_L01D0P8fEeW45bORGB4c_A" name="E1"/> <packagedElement xmi:type="uml:SignalEvent" xmi:id="_NeH84P8fEeW45bORGB4c_A" name="SignalEventE1" signal="_L01D0P8fEeW45bORGB4c_A"/> </uml:Model>
Tip | |
---|---|
When opening existing uml model defined as uml, you’ll have three
files, |
After uml file is in place in your project, it can be imported into
configuration using StateMachineModelConfigurer
where
StateMachineModelFactory
is associated with a model.
UmlStateMachineModelFactory
is a special factory which knows how to
process Eclipse Papyrus generated uml structure. Source uml file can
either be given as a Spring Resource
or a normal location string.
@Configuration @EnableStateMachine public static class Config1 extends StateMachineConfigurerAdapter<String, String> { @Override public void configure(StateMachineModelConfigurer<String, String> model) throws Exception { model .withModel() .factory(modelFactory()); } @Bean public StateMachineModelFactory<String, String> modelFactory() { return new UmlStateMachineModelFactory("classpath:org/springframework/statemachine/uml/docs/simple-machine.uml"); } }
As usually Spring StateMachine is working with Guards and Actions which are defined as bean, those need to be hooked into uml by its internal modeling structure. In a below sections you will see how customized bean references are defined within uml definitions. Thought it is also possible to register particular methods manually without defining those as beans.
If UmlStateMachineModelFactory
is created as a bean its
ResourceLoader
is wired automatically to find registered actions and
guards. It’s also possible to manually define a
StateMachineComponentResolver
which will then be used to find these
components. Factory also have methods registerAction and
registerGuard which can be used to register these components.
Uml model is relatively loose what comes for the implementation like Spring StateMachine itself. There are choices what implementation need to take for uml support as it leaves a lot of features and functionalities for an implementation to decide. Below sections go through how Spring StateMachine will implement uml model based on Eclipse Papyrus plugin.
Let’s start by creating an empty state machine model.
You’ll start by creating a new model and giving it a name.
Then you need to choose a StateMachine Diagram.
You end up having an empty state machine.
In above sample named model
you’ll end up three files, model.di
,
model.notation
and model.uml
which can then be used in any other
eclipse instance and model.uml
can be used by importing it into a
Spring Statemachine.
State identifier is simply coming from a component name in a diagram. You must have initial state in your machine which is done by adding Initial and then drawing a transition to your own initial state.
In above we added one state S1
, initial state, and draw a transition
between those two to indicate that S1
is an initial state.
In above we added a second state S2
and added a transition between
those two.
To associate an event for a transition you need to create a Signal
E1
. Done from RootElement→New Child→Signal.
And then SignalEvent
with defined signal E1
. Done from
RootElement→New Child→SignalEvent.
Transition is simply created by drawing transition line between
source and target states. In above we have states S1
and S2
and
anonymous trasition between those two. We want to associate event
E1
with that transition. We choose a transition, create a new
trigger and define SignalEventE1
for that.
This will give you something like shown below.
Tip | |
---|---|
If |
Transition can also happen based on timed events. Spring Statemachine support two types of timers, ones which fires continously on a background and ones which fires once with a delay when state is entered.
Add new TimeEvent
child to Model Explorer, modify When as
expression defined as LiteralInteger. Value of it is then timer as
milliseconds. Is Relative is left to false making timer to fire
continously.
To define one timed based event when state is entered it’s exactly same as above but Is Relative is now defined as true.
Then what is left for user is to pick these time events instead of signal event for a particular transition.
State entry and exit actions can be associated by using a behaviour, more about this in Section 27.9, “Define Bean Reference”.
Guard can be defined by first adding Constraint and then defining its Specification as OpaqueExpression which works in a same way than Section 27.9, “Define Bean Reference”.
When there is a need to make a bean reference in any uml effect,
action or guard, supported method to do that is via
FunctionBehavior
or OpaqueBehavior
where defined language needs to
be bean
and language body having a bean reference id.