Fix proper transition into super state
- Big conceptual changes how state transitions are handled which now allows more easy ways to figure out what to do and where to go. - Exposing more info via State interface - Adding tests to samples - Fixes #30
This commit is contained in:
@@ -25,7 +25,7 @@ public class Application {
|
||||
throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(States.S0)
|
||||
.initial(States.S0, fooAction())
|
||||
.state(States.S0)
|
||||
.and()
|
||||
.withStates()
|
||||
@@ -95,9 +95,18 @@ public class Application {
|
||||
.withExternal()
|
||||
.source(States.S211).target(States.S0).event(Events.G)
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(States.S21).target(States.S21).event(Events.H)
|
||||
.guard(fooGuard())
|
||||
.withInternal()
|
||||
.source(States.S0).event(Events.H)
|
||||
.guard(foo0Guard())
|
||||
.action(fooAction())
|
||||
.and()
|
||||
.withInternal()
|
||||
.source(States.S2).event(Events.H)
|
||||
.guard(foo1Guard())
|
||||
.action(fooAction())
|
||||
.and()
|
||||
.withInternal()
|
||||
.source(States.S1).event(Events.H)
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(States.S11).target(States.S12).event(Events.I);
|
||||
@@ -105,8 +114,13 @@ public class Application {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FooGuard fooGuard() {
|
||||
return new FooGuard();
|
||||
public FooGuard foo0Guard() {
|
||||
return new FooGuard(0);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FooGuard foo1Guard() {
|
||||
return new FooGuard(1);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -134,7 +148,14 @@ public class Application {
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<States, Events> context) {
|
||||
context.getExtendedState().getVariables().put("foo", 1);
|
||||
Object foo = context.getExtendedState().getVariables().get("foo");
|
||||
if (foo instanceof Integer && ((Integer)foo) == 0) {
|
||||
context.getExtendedState().getVariables().put("foo", 1);
|
||||
} else if (foo instanceof Integer && ((Integer)foo) == 1) {
|
||||
context.getExtendedState().getVariables().put("foo", 0);
|
||||
} else {
|
||||
context.getExtendedState().getVariables().put("foo", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,10 +164,16 @@ public class Application {
|
||||
// tag::snippetE[]
|
||||
private static class FooGuard implements Guard<States, Events> {
|
||||
|
||||
private final int match;
|
||||
|
||||
public FooGuard(int match) {
|
||||
this.match = match;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(StateContext<States, Events> context) {
|
||||
Object foo = context.getExtendedState().getVariables().get("foo");
|
||||
return !(foo == null || !foo.equals(1));
|
||||
return !(foo == null || !foo.equals(match));
|
||||
}
|
||||
}
|
||||
// end::snippetE[]
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
+---------------------------------------------------------------------------------------------+
|
||||
| entry/ |
|
||||
| exit/ |
|
||||
| H/[foo.equals(0)]; |
|
||||
| |
|
||||
| +-------------------------+ +--------------------------------------------+ |
|
||||
| *-->| S1 | | S2 | |
|
||||
| +-------------------------+ +--------------------------------------------+ |
|
||||
| | entry/ | C | entry/ H | |
|
||||
| D | exit/ |----->| exit/ +-------------------+ | |
|
||||
|<----------| | | | H[foo.equals(1)]; | | |
|
||||
| | +---------------+ | C | +------------------------------+ | | |
|
||||
| | *-->| S11 | |<-----| *-->| S21 |<--+ | |
|
||||
| | entry/ | C | entry/ | |
|
||||
| D | exit/ |----->| exit/ | |
|
||||
|<----------| H/ | | H/[foo.equals(1)]; | |
|
||||
| | | | | |
|
||||
| | +---------------+ | C | +------------------------------+ | |
|
||||
| | *-->| S11 | |<-----| *-->| S21 | | |
|
||||
| | +---------------+ | | +------------------------------+ | |
|
||||
| +--| | entry/ | | F | | entry/ | | |
|
||||
| A| | | exit/ |<---------| | exit/ | | |
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.listener.StateMachineListener;
|
||||
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
import demo.CommonConfiguration;
|
||||
import demo.showcase.Application.Events;
|
||||
@@ -48,11 +49,12 @@ public class ShowcaseTests {
|
||||
|
||||
@Test
|
||||
public void testA() throws Exception {
|
||||
listener.reset(1, 2, 2);
|
||||
listener.reset(1, 2, 2, 1);
|
||||
machine.sendEvent(Events.A);
|
||||
listener.stateChangedLatch.await(1, TimeUnit.SECONDS);
|
||||
listener.stateEnteredLatch.await(1, TimeUnit.SECONDS);
|
||||
listener.stateExitedLatch.await(1, TimeUnit.SECONDS);
|
||||
listener.transitionLatch.await(1, TimeUnit.SECONDS);
|
||||
assertThat(machine.getState().getIds(), contains(States.S0, States.S1, States.S11));
|
||||
assertThat(listener.statesEntered.size(), is(2));
|
||||
assertThat(listener.statesEntered.get(0).getId(), is(States.S1));
|
||||
@@ -60,6 +62,7 @@ public class ShowcaseTests {
|
||||
assertThat(listener.statesExited.size(), is(2));
|
||||
assertThat(listener.statesExited.get(0).getId(), is(States.S11));
|
||||
assertThat(listener.statesExited.get(1).getId(), is(States.S1));
|
||||
assertThat(listener.transitionCount, is(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -91,6 +94,20 @@ public class ShowcaseTests {
|
||||
assertThat(listener.statesEntered.get(1).getId(), is(States.S11));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testD() throws Exception {
|
||||
listener.reset(3, 3, 0);
|
||||
machine.sendEvent(Events.D);
|
||||
listener.stateChangedLatch.await(1, TimeUnit.SECONDS);
|
||||
listener.stateEnteredLatch.await(1, TimeUnit.SECONDS);
|
||||
assertThat(machine.getState().getIds(), contains(States.S0, States.S1, States.S11));
|
||||
assertThat(listener.statesEntered.size(), is(3));
|
||||
assertThat(listener.statesEntered.get(0).getId(), is(States.S0));
|
||||
assertThat(listener.statesEntered.get(1).getId(), is(States.S1));
|
||||
assertThat(listener.statesEntered.get(2).getId(), is(States.S11));
|
||||
assertThat(listener.statesExited.size(), is(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCD() throws Exception {
|
||||
listener.reset(1, 3, 0);
|
||||
@@ -120,6 +137,46 @@ public class ShowcaseTests {
|
||||
assertThat(listener.statesExited.get(0).getId(), is(States.S11));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testH() throws Exception {
|
||||
listener.reset(0, 0, 0, 1);
|
||||
machine.sendEvent(Events.H);
|
||||
listener.transitionLatch.await(1, TimeUnit.SECONDS);
|
||||
assertThat(listener.transitionCount, is(1));
|
||||
assertThat(listener.transitions.get(0).getSource().getId(), is(States.S1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCH() throws Exception {
|
||||
machine.sendEvent(Events.C);
|
||||
listener.reset(0, 0, 0, 1);
|
||||
machine.sendEvent(Events.H);
|
||||
listener.transitionLatch.await(1, TimeUnit.SECONDS);
|
||||
assertThat(listener.transitionCount, is(1));
|
||||
assertThat(listener.transitions.get(0).getSource().getId(), is(States.S0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testACH() throws Exception {
|
||||
machine.sendEvent(Events.A);
|
||||
machine.sendEvent(Events.C);
|
||||
listener.reset(0, 0, 0, 1);
|
||||
machine.sendEvent(Events.H);
|
||||
listener.transitionLatch.await(1, TimeUnit.SECONDS);
|
||||
assertThat(listener.transitionCount, is(1));
|
||||
assertThat(listener.transitions.get(0).getSource().getId(), is(States.S2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testE() throws Exception {
|
||||
listener.reset(1, 2, 3, 0);
|
||||
machine.sendEvent(Events.E);
|
||||
listener.stateChangedLatch.await(1, TimeUnit.SECONDS);
|
||||
assertThat(machine.getState().getIds(), contains(States.S0, States.S2, States.S21, States.S211));
|
||||
assertThat(listener.statesExited.size(), is(2));
|
||||
assertThat(listener.statesEntered.size(), is(3));
|
||||
}
|
||||
|
||||
static class Config {
|
||||
|
||||
@Autowired
|
||||
@@ -138,8 +195,11 @@ public class ShowcaseTests {
|
||||
volatile CountDownLatch stateChangedLatch = new CountDownLatch(1);
|
||||
volatile CountDownLatch stateEnteredLatch = new CountDownLatch(3);
|
||||
volatile CountDownLatch stateExitedLatch = new CountDownLatch(0);
|
||||
volatile CountDownLatch transitionLatch = new CountDownLatch(0);
|
||||
volatile List<Transition<States, Events>> transitions = new ArrayList<Transition<States,Events>>();
|
||||
List<State<States, Events>> statesEntered = new ArrayList<State<States,Events>>();
|
||||
List<State<States, Events>> statesExited = new ArrayList<State<States,Events>>();
|
||||
volatile int transitionCount = 0;
|
||||
|
||||
@Override
|
||||
public void stateChanged(State<States, Events> from, State<States, Events> to) {
|
||||
@@ -158,12 +218,26 @@ public class ShowcaseTests {
|
||||
stateExitedLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transition(Transition<States, Events> transition) {
|
||||
transitions.add(transition);
|
||||
transitionLatch.countDown();
|
||||
transitionCount++;
|
||||
}
|
||||
|
||||
public void reset(int c1, int c2, int c3) {
|
||||
reset(c1, c2, c3, 0);
|
||||
}
|
||||
|
||||
public void reset(int c1, int c2, int c3, int c4) {
|
||||
stateChangedLatch = new CountDownLatch(c1);
|
||||
stateEnteredLatch = new CountDownLatch(c2);
|
||||
stateExitedLatch = new CountDownLatch(c3);
|
||||
transitionLatch = new CountDownLatch(c4);
|
||||
statesEntered.clear();
|
||||
statesExited.clear();
|
||||
transitionCount = 0;
|
||||
transitions.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user