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 518c0756..a388f7a8 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 @@ -27,6 +27,7 @@ import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Queue; +import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.commons.logging.Log; @@ -55,6 +56,7 @@ import org.springframework.statemachine.state.State; import org.springframework.statemachine.transition.Transition; import org.springframework.statemachine.transition.TransitionKind; import org.springframework.statemachine.trigger.DefaultTriggerContext; +import org.springframework.statemachine.trigger.EventTrigger; import org.springframework.statemachine.trigger.TimerTrigger; import org.springframework.statemachine.trigger.Trigger; import org.springframework.statemachine.trigger.TriggerListener; @@ -200,6 +202,7 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport for (Transition transition : transitions) { Trigger trigger = transition.getTrigger(); if (trigger != null) { + // we have same triggers with different transitions triggerToTransitionMap.put(trigger, transition); } } @@ -435,31 +438,71 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport log.debug("Process trigger queue"); TriggerQueueItem queueItem = null; while ((queueItem = triggerQueue.poll()) != null) { + + if (currentState == null) { + continue; + } + Message queuedEvent = queueItem.message; - Transition transition = triggerToTransitionMap.get(queueItem.trigger); - StateContext stateContext = new DefaultStateContext(queuedEvent != null ? queuedEvent.getHeaders() : null, extendedState, transition, this); - if (transition == null) { - continue; - } + E event = queuedEvent != null ? queuedEvent.getPayload() : null; - State source = transition.getSource(); - if (source == null || currentState == null) { - continue; - } - if (!StateMachineUtils.containsAtleastOne(source.getIds(), currentState.getIds())) { - continue; - } + // need all transitions trigger could match, event trigger may match multiple + // need to go up from substates and ask if trigger transit, if not check super + ArrayList> trans = new ArrayList>(); - notifyTransitionStart(transition); - callHandlers(transition.getSource(), transition.getTarget(), queuedEvent); - boolean transit = transition.transit(stateContext); - if (transit) { - if (transition.getKind() != TransitionKind.INTERNAL) { - switchToState(transition.getTarget(), queuedEvent, transition); + if (event != null) { + ArrayList ids = new ArrayList(currentState.getIds()); + Collections.reverse(ids); + for (S id : ids) { + for (Entry, Transition> e : triggerToTransitionMap.entrySet()) { + Trigger tri = e.getKey(); + E ee = tri.getEvent(); + Transition tra = e.getValue(); + if (event == ee) { + if (tra.getSource().getId() == id && !trans.contains(tra)) { + trans.add(tra); + continue; + } + } + } } - notifyTransition(transition); } - notifyTransitionEnd(transition); + + // most likely timer + if (trans.isEmpty()) { + trans.add(triggerToTransitionMap.get(queueItem.trigger)); + } + + // go through candidates and transit max one + for (Transition t : trans) { + StateContext stateContext = new DefaultStateContext( + queuedEvent != null ? queuedEvent.getHeaders() : null, extendedState, t, this); + if (t == null) { + continue; + } + State source = t.getSource(); + if (source == null) { + continue; + } + if (!StateMachineUtils.containsAtleastOne(source.getIds(), currentState.getIds())) { + continue; + } + boolean transit = t.transit(stateContext); + if (transit) { + // TODO: should change trasition api so that we can ask + // if transition will transit so that we can post + // accurate notifyTransitionStart + notifyTransitionStart(t); + callHandlers(t.getSource(), t.getTarget(), queuedEvent); + if (t.getKind() != TransitionKind.INTERNAL) { + switchToState(t.getTarget(), queuedEvent, t); + } + notifyTransition(t); + notifyTransitionEnd(t); + break; + } + + } } } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/EventTrigger.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/EventTrigger.java index 67d83ccf..f6ef07f4 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/EventTrigger.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/EventTrigger.java @@ -35,4 +35,9 @@ public class EventTrigger implements Trigger { // no-opt } + @Override + public E getEvent() { + return event; + } + } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/TimerTrigger.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/TimerTrigger.java index 944f8b32..77bf96cb 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/TimerTrigger.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/TimerTrigger.java @@ -41,6 +41,11 @@ public class TimerTrigger extends LifecycleObjectSupport implements Trigge triggerListener.register(listener); } + @Override + public E getEvent() { + return null; + } + @Override protected void doStart() { scheduled = getTaskScheduler().scheduleAtFixedRate(new Runnable() { diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/Trigger.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/Trigger.java index ae482333..253f1004 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/Trigger.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/trigger/Trigger.java @@ -43,4 +43,12 @@ public interface Trigger { */ void addTriggerListener(TriggerListener listener); + /** + * Gets the event associated with this trigger. It is possible that there + * are no event association. + * + * @return the event + */ + E getEvent(); + }