From 347e1d709564d8dcdc0446d9e99b79bcdd1aa6d6 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sun, 24 Apr 2016 17:38:20 +0100 Subject: [PATCH] Fix state exit - Fix case where linked pseudostates may cause substate not exited properly. - Tests coming in other commit. - Fixes #208 --- .../support/AbstractStateMachine.java | 9 +++++++ .../support/StateMachineUtils.java | 27 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java index c27fa999..ab995be0 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java @@ -754,10 +754,18 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo } else if (kind == PseudoStateKind.ENTRY) { StateContext stateContext = buildStateContext(Stage.STATE_CHANGED, message, transition, stateMachine); State toState = state.getPseudoState().entry(stateContext); + while (toState != null && toState.getPseudoState() != null + && toState.getPseudoState().getKind() != PseudoStateKind.INITIAL) { + toState = toState.getPseudoState().entry(stateContext); + } setCurrentState(toState, message, transition, true, stateMachine); } else if (kind == PseudoStateKind.EXIT) { StateContext stateContext = buildStateContext(Stage.STATE_CHANGED, message, transition, stateMachine); State toState = state.getPseudoState().entry(stateContext); + while (toState != null && toState.getPseudoState() != null + && toState.getPseudoState().getKind() != PseudoStateKind.INITIAL) { + toState = toState.getPseudoState().entry(stateContext); + } setCurrentState(toState, message, transition, true, stateMachine); } else if (kind == PseudoStateKind.FORK) { ForkPseudoState fps = (ForkPseudoState) state.getPseudoState(); @@ -982,6 +990,7 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo } else if (isTargetSubOfOtherState) { } else if (!isSubOfSource && !isSubOfTarget && findDeep == null) { } else if (!isSubOfSource && !isSubOfTarget && (transition.getSource() == currentState && StateMachineUtils.isSubstate(currentState, transition.getTarget()))) { + } else if (StateMachineUtils.isNormalPseudoState(transition.getTarget())) { } else if (!isSubOfSource && !isSubOfTarget) { return; } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/StateMachineUtils.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/StateMachineUtils.java index e1d59e30..4ccf680b 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/StateMachineUtils.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/StateMachineUtils.java @@ -18,6 +18,8 @@ package org.springframework.statemachine.support; import java.util.ArrayList; import java.util.Collection; +import org.springframework.statemachine.state.PseudoState; +import org.springframework.statemachine.state.PseudoStateKind; import org.springframework.statemachine.state.State; import org.springframework.util.ObjectUtils; @@ -68,6 +70,31 @@ public abstract class StateMachineUtils { return false; } + /** + * Checks if state is a normal pseudo state, meaning it is a pseudostate + * and its kind is not initial or end. + * + * @param the type of state + * @param the type of event + * @param state the state + * @return true, if is normal pseudo state + */ + public static boolean isNormalPseudoState(State state) { + if (state == null) { + return false; + } + PseudoState pseudoState = state.getPseudoState(); + if (pseudoState == null) { + return false; + } + PseudoStateKind kind = pseudoState.getKind(); + if (kind == PseudoStateKind.INITIAL || kind == PseudoStateKind.END) { + return false; + } else { + return true; + } + } + public static Collection toStringCollection(Collection collection) { Collection c = new ArrayList(); for (S item : collection) {