spring state machine changing to one of two possible states based on action
<p>i'm having trouble configuring my SSM for a very simple scenario:</p>

<p><a href="https://i.stack.imgur.com/0zv8P.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0zv8P.png" alt="enter image description here"></a></p>

<p>the culprit is the 'validation' action that needs to happen when the <strong>log_on</strong> event is fired. i re-read the SSM documentation and am not sure if this is a 'fork', 'guard' or a hierarchical configuration.</p>

<p>the 'action' is performed here:</p>

<pre><code>@Component
public class LogonValidationAction implements Action&lt;PickStates, PickEvents&gt; {

Logger logger = LogManager.getLogger();

volatile int counter = 0;

@Override
public void execute(StateContext&lt;PickStates, PickEvents&gt; context) {
    String eventName = context.getEvent().name();
    logger.info("executing {} for event {}", LogonValidationAction.class.getName(), eventName);

    // basically, if success, send success, if failure, send failure
    // for testing
    if(counter % 2 == 0)
        context.getStateMachine().sendEvent(PickEvents.logon_sucess);
    else
        context.getStateMachine().sendEvent(PickEvents.logon_fail);
}
}
</code></pre>

<p>i am using 'counter' in my test to direct the flow to either 'failure' (logged_off state remains) or 'success' (state changes to logged_on).</p>

<p>here's the configuration:</p>

<pre><code>@Configuration
@EnableStateMachineFactory
public class Config extends EnumStateMachineConfigurerAdapter&lt;PickStates, PickEvents&gt;{

@Autowired
StateMachineListener stateMachineListener;

@Autowired
LogonValidationAction logonValidationAction;

@Override
public void configure(StateMachineStateConfigurer&lt;PickStates, PickEvents&gt; states) throws Exception {
    states
        .withStates()
        .initial(PickStates.logged_off)
        .state(PickStates.logged_on)
        .states(EnumSet.allOf(PickStates.class));
}

@Override
public void configure(StateMachineTransitionConfigurer&lt;PickStates, PickEvents&gt; transitions) throws Exception {
    transitions
        .withExternal()
        .source(PickStates.logged_off)
        .target(PickStates.logged_on)
        .event(PickEvents.log_on)
        .action(logonValidationAction)
        .and()
        .withExternal()
        .source(PickStates.logged_on)
        .target(PickStates.logged_off)
        .event(PickEvents.log_off);
}

@Override
public void configure(StateMachineConfigurationConfigurer&lt;PickStates, PickEvents&gt; config) throws Exception {
    config
        .withConfiguration()
        .autoStartup(true)
        .listener(stateMachineListener);
}
}
</code></pre>

<p>this is the failing test (expecting 'logged_off' when the action fires the logon_fail event):</p>

<pre><code>@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class EzpickStateMachineTest {

Logger logger = LogManager.getLogger();

@Autowired
StateMachineFactory&lt;PickStates, PickEvents&gt; stateMachineFactory;

// for testing so can toggle success/failure when logging in
@Autowired
LogonValidationAction logonValidationAction;

@Test
public void failLogon() throws Exception {
    StateMachine&lt;PickStates, PickEvents&gt; stateMachine = stateMachineFactory.getStateMachine();

    stateMachine.start();

    // when sm starts, state is 'logged_off'
    assertThat(stateMachine.getState().getId().name(), is(PickStates.logged_off.name()));

    // odd numbers fire 'failure' event
    logonValidationAction.setCounter(1);

    stateMachine.sendEvent(PickEvents.log_on);

    // if logon fails, state is 'logged_off'
    assertThat(stateMachine.getState().getId().name(), is(PickStates.logged_off.name()));
}
}
</code></pre>