You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a statemachine defined with two fork/joins and with each of those submachines having their own fork/join. I have tested that all states correctly transition including all sub states and fork/joins all the way to the final end state. That is great!, however, I discovered two problems related to actions on sub-submachines (2 levels down):
Transitioning within a sub-submachine (2 levels down) region never invokes the exit action (but mysteriously, they all invoke their entry actions)
Transitioning out of a join from the sub-submachine into another state results in a StateContext containing no useful information on what state is involved (I assume this is because its coming from a join, but I though an entry Action would at least have the target non-null).
Full example showing this issue (will echo entry and exit, as well as a tests on expected states entered/exited):
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.action.Action;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.statemachine.config.StateMachineBuilder.Builder;
public class MissingActionExecution {
private List<String> statesEntered_;
private List<String> statesExited_;
public void before()
{
statesEntered_ = new ArrayList<String>();
statesExited_ = new ArrayList<String>();
}
public static void main(String[] args) throws Exception {
MissingActionExecution missingActions = new MissingActionExecution();
missingActions.before();
missingActions.run();
}
public void run() throws Exception
{
Builder<String,String> builder = StateMachineBuilder.builder();
builder.configureStates().withStates().initial("startState")
.fork("forkState")
.state("state2")
.join("joinState")
.state("state3", new EchoEntryAction<String,String>("state3"), new EchoExitAction<String,String>("state3"))
.end("endState")
.and()
.withStates()
.parent("state2")
.initial("state21SubStart")
.state("state21SubStateA", new EchoEntryAction<String,String>("state21SubStateA"), new EchoExitAction<String,String>("state21SubStateA"))
.fork("forkInState21")
.state("state21SubStateB")
.join("joinInState21")
.state("state21SubStateC", new EchoEntryAction<String,String>("state21SubStateC"), new EchoExitAction<String,String>("state21SubStateC"))
.end("state21SubEnd")
.and()
.withStates()
.parent("state2")
.initial("state22SubStart")
.state("state22SubStateA", new EchoEntryAction<String,String>("state22SubStateA"), new EchoExitAction<String,String>("state22SubStateA"))
.fork("forkInState22")
.state("state22SubStateB")
.join("joinInState22")
.state("state22SubStateC", new EchoEntryAction<String,String>("state22SubStateC"), new EchoExitAction<String,String>("state22SubStateC"))
.end("state22SubEnd")
.and()
.withStates()
.parent("state21SubStateB")
.initial("state21SubStateBStart")
.state("state21SubStateBA", new EchoEntryAction<String,String>("state21SubStateBA"), new EchoExitAction<String,String>("state21SubStateBA"))
.state("state21SubStateBB", new EchoEntryAction<String,String>("state21SubStateBB"), new EchoExitAction<String,String>("state21SubStateBB"))
.state("state21SubStateBC", new EchoEntryAction<String,String>("state21SubStateBC"), new EchoExitAction<String,String>("state21SubStateBC"))
.end("state21SubStateBEnd")
.and()
.withStates()
.parent("state21SubStateB")
.initial("state211SubStateBStart")
.state("state211SubStateBA", new EchoEntryAction<String,String>("state211SubStateBA"), new EchoExitAction<String,String>("state211SubStateBA"))
.state("state211SubStateBB", new EchoEntryAction<String,String>("state211SubStateBB"), new EchoExitAction<String,String>("state211SubStateBB"))
.state("state211SubStateBC", new EchoEntryAction<String,String>("state211SubStateBC"), new EchoExitAction<String,String>("state211SubStateBC"))
.end("state211SubStateBEnd")
.and()
.withStates()
.parent("state22SubStateB")
.initial("state22SubStateBStart")
.state("state22SubStateBA", new EchoEntryAction<String,String>("state22SubStateBA"), new EchoExitAction<String,String>("state22SubStateBA"))
.state("state22SubStateBB", new EchoEntryAction<String,String>("state22SubStateBB"), new EchoExitAction<String,String>("state22SubStateBB"))
.state("state22SubStateBC", new EchoEntryAction<String,String>("state22SubStateBC"), new EchoExitAction<String,String>("state22SubStateBC"))
.end("state22SubStateBEnd")
.and()
.withStates()
.parent("state22SubStateB")
.initial("state222SubStateBStart")
.state("state222SubStateBA", new EchoEntryAction<String,String>("state222SubStateBA"), new EchoExitAction<String,String>("state222SubStateBA"))
.state("state222SubStateBB", new EchoEntryAction<String,String>("state222SubStateBB"), new EchoExitAction<String,String>("state222SubStateBB"))
.state("state222SubStateBC", new EchoEntryAction<String,String>("state222SubStateBC"), new EchoExitAction<String,String>("state222SubStateBC"))
.end("state222SubStateBEnd");
builder.configureTransitions()
.withExternal().source("startState").target("state2").and()
.withFork().source("forkState").target("state21SubStart").target("state22SubStart").and()
.withExternal().source("state21SubStart").target("state21SubStateA").and()
.withExternal().source("state21SubStateA").target("state21SubStateB").and()
.withFork().source("forkInState21").target("state21SubStateBStart").target("state211SubStateBStart").and()
.withExternal().source("state21SubStateBStart").target("state21SubStateBA").and()
.withExternal().source("state21SubStateBA").target("state21SubStateBB").and()
.withExternal().source("state21SubStateBB").target("state21SubStateBC").and()
.withExternal().source("state21SubStateBC").target("state21SubStateBEnd").and()
.withExternal().source("state211SubStateBStart").target("state211SubStateBA").and()
.withExternal().source("state211SubStateBA").target("state211SubStateBB").and()
.withExternal().source("state211SubStateBB").target("state211SubStateBC").and()
.withExternal().source("state211SubStateBC").target("state211SubStateBEnd").and()
.withJoin().source("state21SubStateBEnd").source("state211SubStateBEnd").target("joinInState21").and()
.withExternal().source("joinInState21").target("state21SubStateC").and()
.withExternal().source("state21SubStateC").target("state21SubEnd").and()
.withExternal().source("state22SubStart").target("state22SubStateA").and()
.withExternal().source("state22SubStateA").target("state22SubStateB").and()
.withFork().source("forkInState22").target("state22SubStateBStart").target("state222SubStateBStart").and()
.withExternal().source("state22SubStateBStart").target("state22SubStateBA").and()
.withExternal().source("state22SubStateBA").target("state22SubStateBB").and()
.withExternal().source("state22SubStateBB").target("state22SubStateBC").and()
.withExternal().source("state22SubStateBC").target("state22SubStateBEnd").and()
.withExternal().source("state222SubStateBStart").target("state222SubStateBA").and()
.withExternal().source("state222SubStateBA").target("state222SubStateBB").and()
.withExternal().source("state222SubStateBB").target("state222SubStateBC").and()
.withExternal().source("state222SubStateBC").target("state222SubStateBEnd").and()
.withJoin().source("state22SubStateBEnd").source("state222SubStateBEnd").target("joinInState22").and()
.withExternal().source("joinInState22").target("state22SubStateC").and()
.withExternal().source("state22SubStateC").target("state22SubEnd").and()
.withJoin().source("state21SubEnd").source("state22SubEnd").target("joinState").and()
.withExternal().source("joinState").target("state3").and()
.withExternal().source("state3").target("endState");
StateMachine<String,String> sm = builder.build();
sm.start();
System.out.println("End State is:" +sm.getState().getIds() + "\n");
Set<String> expected = new HashSet<String>(Arrays.asList(new String[]{
"state21SubStateA",
"state21SubStateBA","state21SubStateBB","state21SubStateBC",
"state211SubStateBA","state211SubStateBB","state211SubStateBC",
"state21SubStateC",
"state22SubStateA",
"state22SubStateBA","state22SubStateBB","state22SubStateBC",
"state222SubStateBA","state222SubStateBB","state222SubStateBC",
"state22SubStateC",
"state3"}));
boolean statesExpectedOnEntry = new HashSet<String>(statesEntered_).equals(expected);
if (!statesExpectedOnEntry)
{
System.out.println("ENTRY TEST FAIL: \nfound:\n" + statesEntered_ + "\nexpected: \n" + expected + "\n");
}
boolean statesExpectedOnExit = new HashSet<String>(statesExited_).equals(expected);
if (!statesExpectedOnExit)
{
System.out.println("EXIT TEST FAIL: \nfound:\n" + statesExited_ + "\nexpected: \n" + expected + "\n");
}
sm.stop();
}
private class EchoEntryAction<S, E> implements Action<S, E> {
private String state_;
public EchoEntryAction(String state)
{
state_= state;
}
public void execute(StateContext<S, E> context) {
if (context == null || context.getTarget() == null)
{
System.out.println("Entered NULL TARGET: " + state_);
//statesEntered_.add(state_);
return;
}
statesEntered_.add((String)context.getTarget().getId());
System.out.println("Entered: " + context.getTarget().getId());
}
}
private class EchoExitAction<S, E> implements Action<S, E> {
private String state_;
public EchoExitAction(String state)
{
state_= state;
}
public void execute(StateContext<S, E> context) {
if (context == null || context.getSource() == null)
{
System.out.println("Exited NULL SOURCE: " + state_);
//statesExited_.add(state_);
return;
}
statesExited_.add((String)context.getSource().getId());
System.out.println("Exited: " + context.getSource().getId());
}
}
}
The text was updated successfully, but these errors were encountered:
Hi there,
I have a statemachine defined with two fork/joins and with each of those submachines having their own fork/join. I have tested that all states correctly transition including all sub states and fork/joins all the way to the final end state. That is great!, however, I discovered two problems related to actions on sub-submachines (2 levels down):
Transitioning within a sub-submachine (2 levels down) region never invokes the exit action (but mysteriously, they all invoke their entry actions)
Transitioning out of a join from the sub-submachine into another state results in a StateContext containing no useful information on what state is involved (I assume this is because its coming from a join, but I though an entry Action would at least have the target non-null).
Full example showing this issue (will echo entry and exit, as well as a tests on expected states entered/exited):
The text was updated successfully, but these errors were encountered: