Direct region entry doesn't bypass initial state entry
- Enhance state context to have more info about target states which is needed to make a proper decision if region needs to be started. - Fix RegionState to not to start if it looks like direct entry will be done later. - Relates to #221
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.statemachine;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
@@ -104,7 +106,17 @@ public interface StateContext<S, E> {
|
||||
*
|
||||
* @return the source state
|
||||
*/
|
||||
State<S,E> getSource();
|
||||
State<S, E> getSource();
|
||||
|
||||
/**
|
||||
* Gets the source states of this context. Multiple sources are
|
||||
* only valid during a context when machine is joining from multiple
|
||||
* orthogonal regions.
|
||||
*
|
||||
* @return the source state
|
||||
* @see #getSource()
|
||||
*/
|
||||
Collection<State<S, E>> getSources();
|
||||
|
||||
/**
|
||||
* Gets the target state of this context. Generally target
|
||||
@@ -113,7 +125,17 @@ public interface StateContext<S, E> {
|
||||
*
|
||||
* @return the target state
|
||||
*/
|
||||
State<S,E> getTarget();
|
||||
State<S, E> getTarget();
|
||||
|
||||
/**
|
||||
* Gets the target states of this context. Multiple targets are
|
||||
* only valid during a context when machine is forking into multiple
|
||||
* orthogonal regions.
|
||||
*
|
||||
* @return the target states
|
||||
* @see #getTarget()
|
||||
*/
|
||||
Collection<State<S, E>> getTargets();
|
||||
|
||||
/**
|
||||
* Gets the exception associated with a context.
|
||||
@@ -138,5 +160,4 @@ public interface StateContext<S, E> {
|
||||
TRANSITION_START,
|
||||
TRANSITION_END;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@ package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
@@ -159,14 +158,8 @@ public class RegionState<S, E> extends AbstractState<S, E> {
|
||||
if (getPseudoState() != null && getPseudoState().getKind() == PseudoStateKind.INITIAL) {
|
||||
for (Region<S, E> region : getRegions()) {
|
||||
boolean start = true;
|
||||
PseudoState<S, E> ps = context.getTransition().getTarget().getPseudoState();
|
||||
if (ps != null && ps.getKind() == PseudoStateKind.FORK) {
|
||||
List<State<S, E>> forks = ((ForkPseudoState<S, E>)ps).getForks();
|
||||
if (StateMachineUtils.containsAtleastOne(region.getStates(), forks)) {
|
||||
// it looks like fork will take directly into a state so don't start
|
||||
// as we want to bypass initial entry logic.
|
||||
start = false;
|
||||
}
|
||||
if (StateMachineUtils.containsAtleastOne(region.getStates(), context.getTargets())) {
|
||||
start = false;
|
||||
}
|
||||
if (start) {
|
||||
region.start();
|
||||
|
||||
@@ -735,7 +735,7 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
ForkPseudoState<S, E> fps = (ForkPseudoState<S, E>) toState.getPseudoState();
|
||||
for (State<S, E> ss : fps.getForks()) {
|
||||
callPreStateChangeInterceptors(ss, message, transition, stateMachine);
|
||||
setCurrentState(ss, message, transition, false, stateMachine);
|
||||
setCurrentState(ss, message, transition, false, stateMachine, null, fps.getForks());
|
||||
}
|
||||
} else {
|
||||
setCurrentState(toState, message, transition, true, stateMachine);
|
||||
@@ -811,6 +811,12 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
return new DefaultStateContext<S, E>(stage, message, messageHeaders, extendedState, transition, stateMachine, source, target, null);
|
||||
}
|
||||
|
||||
private StateContext<S, E> buildStateContext(Stage stage, Message<E> message, Transition<S,E> transition, StateMachine<S, E> stateMachine, Collection<State<S, E>> sources, Collection<State<S, E>> targets) {
|
||||
MessageHeaders messageHeaders = message != null ? message.getHeaders() : new MessageHeaders(
|
||||
new HashMap<String, Object>());
|
||||
return new DefaultStateContext<S, E>(stage, message, messageHeaders, extendedState, transition, stateMachine, null, null, sources, targets, null);
|
||||
}
|
||||
|
||||
private State<S, E> findDeepParent(State<S, E> state) {
|
||||
for (State<S, E> s : states) {
|
||||
if (s.getStates().contains(state)) {
|
||||
@@ -821,6 +827,11 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
}
|
||||
|
||||
synchronized void setCurrentState(State<S, E> state, Message<E> message, Transition<S, E> transition, boolean exit, StateMachine<S, E> stateMachine) {
|
||||
setCurrentState(state, message, transition, exit, stateMachine, null, null);
|
||||
}
|
||||
|
||||
synchronized void setCurrentState(State<S, E> state, Message<E> message, Transition<S, E> transition, boolean exit,
|
||||
StateMachine<S, E> stateMachine, Collection<State<S, E>> sources, Collection<State<S, E>> targets) {
|
||||
|
||||
State<S, E> findDeep = findDeepParent(state);
|
||||
boolean isTargetSubOf = false;
|
||||
@@ -901,7 +912,7 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
}
|
||||
currentState = findDeep;
|
||||
if (shouldTryEntry) {
|
||||
entryToState(currentState, message, transition, stateMachine);
|
||||
entryToState(currentState, message, transition, stateMachine, sources, targets);
|
||||
}
|
||||
|
||||
if (currentState.isSubmachineState()) {
|
||||
@@ -985,11 +996,16 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
}
|
||||
|
||||
private void entryToState(State<S, E> state, Message<E> message, Transition<S, E> transition, StateMachine<S, E> stateMachine) {
|
||||
entryToState(state, message, transition, stateMachine, null, null);
|
||||
}
|
||||
|
||||
private void entryToState(State<S, E> state, Message<E> message, Transition<S, E> transition, StateMachine<S, E> stateMachine,
|
||||
Collection<State<S, E>> sources, Collection<State<S, E>> targets) {
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
log.trace("Trying Enter state=[" + state + "]");
|
||||
StateContext<S, E> stateContext = buildStateContext(Stage.STATE_ENTRY, message, transition, stateMachine);
|
||||
StateContext<S, E> stateContext = buildStateContext(Stage.STATE_ENTRY, message, transition, stateMachine, sources, targets);
|
||||
|
||||
if (transition != null) {
|
||||
State<S, E> findDeep1 = findDeepParent(transition.getTarget());
|
||||
@@ -1026,5 +1042,4 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.statemachine.ExtendedState;
|
||||
@@ -41,6 +43,8 @@ public class DefaultStateContext<S, E> implements StateContext<S, E> {
|
||||
private final StateMachine<S, E> stateMachine;
|
||||
private final State<S, E> source;
|
||||
private final State<S, E> target;
|
||||
private final Collection<State<S, E>> sources;
|
||||
private final Collection<State<S, E>> targets;
|
||||
private final Exception exception;
|
||||
|
||||
/**
|
||||
@@ -67,6 +71,39 @@ public class DefaultStateContext<S, E> implements StateContext<S, E> {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.exception = exception;
|
||||
this.sources = null;
|
||||
this.targets = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new default state context.
|
||||
*
|
||||
* @param stage the stage
|
||||
* @param message the message
|
||||
* @param messageHeaders the message headers
|
||||
* @param extendedState the extended state
|
||||
* @param transition the transition
|
||||
* @param stateMachine the state machine
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param sources the sources
|
||||
* @param targets the targets
|
||||
* @param exception the exception
|
||||
*/
|
||||
public DefaultStateContext(Stage stage, Message<E> message, MessageHeaders messageHeaders, ExtendedState extendedState,
|
||||
Transition<S, E> transition, StateMachine<S, E> stateMachine, State<S, E> source, State<S, E> target,
|
||||
Collection<State<S, E>> sources, Collection<State<S, E>> targets, Exception exception) {
|
||||
this.stage = stage;
|
||||
this.message = message;
|
||||
this.messageHeaders = messageHeaders;
|
||||
this.extendedState = extendedState;
|
||||
this.transition = transition;
|
||||
this.stateMachine = stateMachine;
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.sources = sources;
|
||||
this.targets = targets;
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,11 +156,21 @@ public class DefaultStateContext<S, E> implements StateContext<S, E> {
|
||||
return source != null ? source : (transition != null ? transition.getSource() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<State<S, E>> getSources() {
|
||||
return sources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S, E> getTarget() {
|
||||
return target != null ? target : (transition != null ? transition.getTarget() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<State<S, E>> getTargets() {
|
||||
return targets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
@@ -133,7 +180,6 @@ public class DefaultStateContext<S, E> implements StateContext<S, E> {
|
||||
public String toString() {
|
||||
return "DefaultStateContext [stage=" + stage + ", message=" + message + ", messageHeaders=" + messageHeaders + ", extendedState="
|
||||
+ extendedState + ", transition=" + transition + ", stateMachine=" + stateMachine + ", source=" + source + ", target="
|
||||
+ target + ", exception=" + exception + "]";
|
||||
+ target + ", sources=" + sources + ", targets=" + targets + ", exception=" + exception + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user