From 8d79cb08812e709dfbd3fd72584eec044eb05786 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sun, 15 Mar 2015 16:40:12 +0000 Subject: [PATCH] Fix extended state and @OnTransition handling - Add better support for enums with @OnTransition fixes #25 - Add enum handling with extended state fixes #26 --- .../statemachine/ExtendedState.java | 6 ++-- .../statemachine/StateContext.java | 9 +++++ .../support/AbstractStateMachine.java | 34 +++++++++++++------ .../support/DefaultExtendedState.java | 12 +++---- .../support/DefaultStateContext.java | 18 +++++++--- .../support/StateMachineUtils.java | 27 +++++++++++++++ 6 files changed, 83 insertions(+), 23 deletions(-) diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/ExtendedState.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/ExtendedState.java index 8746c1a7..f58828e1 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/ExtendedState.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/ExtendedState.java @@ -21,17 +21,17 @@ import java.util.Map; * Extended states are used to supplement state machine with a variables. If * extended state is used a complete condition of a state machine is a * combination of its state an extended state variables. - * + * * @author Janne Valkealahti * */ public interface ExtendedState { - + /** * Gets the extended state variables. * * @return the extended state variables */ - Map getVariables(); + Map getVariables(); } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateContext.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateContext.java index fea23026..9eaebce7 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateContext.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/StateContext.java @@ -37,6 +37,15 @@ public interface StateContext { */ MessageHeaders getMessageHeaders(); + /** + * Gets the message header. If header is not a {@code String} object's + * {@link Object#toString()} method is used to resolve a key name. + * + * @param header the header + * @return the message header + */ + Object getMessageHeader(Object header); + /** * Gets the state machine extended state. * 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 ab0fbf4f..7e86f5f8 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 @@ -56,6 +56,7 @@ import org.springframework.statemachine.trigger.TimerTrigger; import org.springframework.statemachine.trigger.Trigger; import org.springframework.statemachine.trigger.TriggerListener; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * Base implementation of a {@link StateMachine} loosely modelled from UML state @@ -277,9 +278,6 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport private void switchToState(State state, Message event, Transition transition) { exitFromState(currentState, event, transition); notifyStateChanged(currentState, state); - - callHandlers(currentState, state, event); - setCurrentState(state, event, transition); // TODO: should handle triggerles transition some how differently @@ -411,6 +409,7 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport } notifyTransitionStart(transition); + callHandlers(transition.getSource(), transition.getTarget(), queuedEvent); boolean transit = transition.transit(stateContext); if (transit && transition.getKind() != TransitionKind.INTERNAL) { switchToState(transition.getTarget(), queuedEvent, transition); @@ -424,16 +423,12 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport } private void callHandlers(State sourceState, State targetState, Message event) { - - - if (sourceState != null && targetState != null) { MessageHeaders messageHeaders = event != null ? event.getHeaders() : new MessageHeaders( new HashMap()); StateContext stateContext = new DefaultStateContext(messageHeaders, extendedState, null); getStateMachineHandlerResults(getStateMachineHandlers(sourceState, targetState), stateContext); } - } private List getStateMachineHandlerResults(List> stateMachineHandlers, final StateContext stateContext) { @@ -475,9 +470,28 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport String source = annotation.source(); String target = annotation.target(); // TODO: need major fixes - String s = sourceState.getIds().iterator().next().toString(); - String t = targetState.getIds().iterator().next().toString(); - if (s.equals(source) && t.equals(target)) { + boolean handle = false; + if (StringUtils.hasText(source) && StringUtils.hasText(target)) { + if (StateMachineUtils.containsAtleastOneEqualString( + StateMachineUtils.toStringCollection(sourceState.getIds()), source) + && StateMachineUtils.containsAtleastOneEqualString( + StateMachineUtils.toStringCollection(targetState.getIds()), target)) { + handle = true; + } + } else if (StringUtils.hasText(source)) { + if (StateMachineUtils.containsAtleastOneEqualString( + StateMachineUtils.toStringCollection(sourceState.getIds()), source)) { + handle = true; + } + } else if (StringUtils.hasText(target)) { + if (StateMachineUtils.containsAtleastOneEqualString( + StateMachineUtils.toStringCollection(targetState.getIds()), target)) { + handle = true; + } + + } + System.out.println("XXX " + source + "/" + target + "/" +handle); + if (handle) { handlersList.add(entry.getValue()); } } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/DefaultExtendedState.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/DefaultExtendedState.java index fd59d0ba..7fe9cdcb 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/DefaultExtendedState.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/DefaultExtendedState.java @@ -22,23 +22,23 @@ import org.springframework.statemachine.ExtendedState; /** * Default implementation of a {@link ExtendedState}. - * + * * @author Janne Valkealahti * */ public class DefaultExtendedState implements ExtendedState { - private final Map variables; - + private final Map variables; + /** * Instantiates a new default extended state. */ public DefaultExtendedState() { - this.variables = new HashMap(); + this.variables = new HashMap(); } - + @Override - public Map getVariables() { + public Map getVariables() { return variables; } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/DefaultStateContext.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/DefaultStateContext.java index c10d7847..375a1657 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/DefaultStateContext.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/DefaultStateContext.java @@ -21,11 +21,11 @@ import org.springframework.statemachine.StateContext; import org.springframework.statemachine.transition.Transition; public class DefaultStateContext implements StateContext { - + private final MessageHeaders messageHeaders; - + private final ExtendedState extendedState; - + private final Transition transition; public DefaultStateContext(MessageHeaders messageHeaders, ExtendedState extendedState, Transition transition) { @@ -39,11 +39,21 @@ public class DefaultStateContext implements StateContext { return messageHeaders; } + @Override + public Object getMessageHeader(Object header) { + if (header instanceof String) { + return messageHeaders.get((String)header); + } else if (header instanceof Enum) { + return messageHeaders.get(((Enum)header).toString()); + } + return null; + } + @Override public ExtendedState getExtendedState() { return extendedState; } - + @Override public Transition getTransition() { return transition; 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 a9a4d946..372e648c 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 @@ -15,6 +15,7 @@ */ package org.springframework.statemachine.support; +import java.util.ArrayList; import java.util.Collection; /** @@ -46,4 +47,30 @@ public abstract class StateMachineUtils { return false; } + public static Collection toStringCollection(Collection collection) { + Collection c = new ArrayList(); + for (S item : collection) { + c.add(item.toString()); + } + return c; + } + + public static boolean containsAtleastOneEqualString(Collection left, String right) { + Collection r = new ArrayList(1); + r.add(right); + return containsAtleastOneEqualString(left, r); + } + + public static boolean containsAtleastOneEqualString(Collection left, Collection right) { + if (left == null || right == null) { + return false; + } + for (String id : left) { + if (right.contains(id)) { + return true; + } + } + return false; + } + }