Fix extended state and @OnTransition handling

- Add better support for enums with @OnTransition fixes #25
- Add enum handling with extended state fixes #26
This commit is contained in:
Janne Valkealahti
2015-03-15 16:40:12 +00:00
parent 9235345a42
commit 8d79cb0881
6 changed files with 83 additions and 23 deletions

View File

@@ -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<String, Object> getVariables();
Map<Object, Object> getVariables();
}

View File

@@ -37,6 +37,15 @@ public interface StateContext<S, E> {
*/
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.
*

View File

@@ -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<S, E> extends LifecycleObjectSupport
private void switchToState(State<S,E> state, Message<E> event, Transition<S,E> 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<S, E> 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<S, E> extends LifecycleObjectSupport
}
private void callHandlers(State<S,E> sourceState, State<S,E> targetState, Message<E> event) {
if (sourceState != null && targetState != null) {
MessageHeaders messageHeaders = event != null ? event.getHeaders() : new MessageHeaders(
new HashMap<String, Object>());
StateContext<S, E> stateContext = new DefaultStateContext<S, E>(messageHeaders, extendedState, null);
getStateMachineHandlerResults(getStateMachineHandlers(sourceState, targetState), stateContext);
}
}
private List<Object> getStateMachineHandlerResults(List<StateMachineHandler<S, E>> stateMachineHandlers, final StateContext<S, E> stateContext) {
@@ -475,9 +470,28 @@ public abstract class AbstractStateMachine<S, E> 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());
}
}

View File

@@ -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<String, Object> variables;
private final Map<Object, Object> variables;
/**
* Instantiates a new default extended state.
*/
public DefaultExtendedState() {
this.variables = new HashMap<String, Object>();
this.variables = new HashMap<Object, Object>();
}
@Override
public Map<String, Object> getVariables() {
public Map<Object, Object> getVariables() {
return variables;
}

View File

@@ -21,11 +21,11 @@ import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.transition.Transition;
public class DefaultStateContext<S, E> implements StateContext<S, E> {
private final MessageHeaders messageHeaders;
private final ExtendedState extendedState;
private final Transition<S,E> transition;
public DefaultStateContext(MessageHeaders messageHeaders, ExtendedState extendedState, Transition<S,E> transition) {
@@ -39,11 +39,21 @@ public class DefaultStateContext<S, E> implements StateContext<S, E> {
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<S, E> getTransition() {
return transition;

View File

@@ -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 <S> Collection<String> toStringCollection(Collection<S> collection) {
Collection<String> c = new ArrayList<String>();
for (S item : collection) {
c.add(item.toString());
}
return c;
}
public static boolean containsAtleastOneEqualString(Collection<String> left, String right) {
Collection<String> r = new ArrayList<String>(1);
r.add(right);
return containsAtleastOneEqualString(left, r);
}
public static boolean containsAtleastOneEqualString(Collection<String> left, Collection<String> right) {
if (left == null || right == null) {
return false;
}
for (String id : left) {
if (right.contains(id)) {
return true;
}
}
return false;
}
}