Add capabilities to provide ActionError in Transition
- Add classes directory to be ignored by git - Doesn't yet handle actions defined for entry, exit or do behariour. - Docs to come when features around error actions are fully implemented. - Fixes #240
This commit is contained in:
committed by
Janne Valkealahti
parent
062bc9aa0e
commit
4c34e46ccf
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@ metastore_db
|
||||
.DS_Store
|
||||
/out/
|
||||
target
|
||||
classes
|
||||
|
||||
@@ -34,5 +34,4 @@ public interface Action<S, E> {
|
||||
* @param context the state context
|
||||
*/
|
||||
void execute(StateContext<S, E> context);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.statemachine.action;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
|
||||
/**
|
||||
* Action Utilities.
|
||||
*/
|
||||
public final class Actions {
|
||||
|
||||
private Actions() {
|
||||
// This helper class should not be instantiated.
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <S> represents states Class
|
||||
* @param <E> represents event Class
|
||||
* @return an empty (Noop) Action.
|
||||
*/
|
||||
public static <S, E> Action<S, E> emptyAction() {
|
||||
return new Action<S, E>() {
|
||||
@Override
|
||||
public void execute(final StateContext<S, E> context) {
|
||||
// Nothing to do;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,6 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -86,6 +77,15 @@ import org.springframework.statemachine.trigger.Trigger;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Base {@link StateMachineFactory} implementation building {@link StateMachine}s.
|
||||
*
|
||||
@@ -694,13 +694,13 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
DefaultExternalTransition<S, E> transition = new DefaultExternalTransition<S, E>(stateMap.get(source),
|
||||
stateMap.get(target), transitionData.getActions(), event, transitionData.getGuard(), trigger,
|
||||
transitionData.getSecurityRule());
|
||||
transitionData.getSecurityRule(), transitionData.getErrorAction());
|
||||
transitions.add(transition);
|
||||
|
||||
} else if (transitionData.getKind() == TransitionKind.INTERNAL) {
|
||||
DefaultInternalTransition<S, E> transition = new DefaultInternalTransition<S, E>(stateMap.get(source),
|
||||
transitionData.getActions(), event, transitionData.getGuard(), trigger,
|
||||
transitionData.getSecurityRule());
|
||||
transitionData.getSecurityRule(), transitionData.getErrorAction());
|
||||
transitions.add(transition);
|
||||
}
|
||||
}
|
||||
@@ -714,7 +714,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
if (source != null && !source.isOrthogonal()) {
|
||||
State<S, E> target = stateMap.get(entry.getKey());
|
||||
DefaultExternalTransition<S, E> transition = new DefaultExternalTransition<S, E>(
|
||||
source, target, null, null, null, null, null);
|
||||
source, target, null, null, null, null, null, null);
|
||||
transitions.add(transition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,6 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.common.annotation.AbstractConfiguredAnnotationBuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationBuilder;
|
||||
@@ -57,6 +51,12 @@ import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@link AnnotationBuilder} for {@link TransitionsData}.
|
||||
*
|
||||
@@ -108,7 +108,7 @@ public class StateMachineTransitionBuilder<S, E>
|
||||
|
||||
@Override
|
||||
protected TransitionsData<S, E> performBuild() throws Exception {
|
||||
return new TransitionsData<S, E>(transitionData, choices, junctions, forks, joins, entryData, exitData, historyData);
|
||||
return new TransitionsData<>(transitionData, choices, junctions, forks, joins, entryData, exitData, historyData);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -174,16 +174,17 @@ public class StateMachineTransitionBuilder<S, E>
|
||||
* @param guard the guard
|
||||
* @param kind the kind
|
||||
* @param securityRule the security rule
|
||||
* @param errorAction the {@link Action} that will be called each time an action is gonna throw an exception.
|
||||
*/
|
||||
public void addTransition(S source, S target, S state, E event, Long period, Integer count, Collection<Action<S, E>> actions,
|
||||
Guard<S, E> guard, TransitionKind kind, SecurityRule securityRule) {
|
||||
Guard<S, E> guard, TransitionKind kind, SecurityRule securityRule, Action<S, E> errorAction) {
|
||||
// if rule not given, get it from global
|
||||
if (securityRule == null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ConfigurationData<S, E> config = getSharedObject(ConfigurationData.class);
|
||||
securityRule = config.getTransitionSecurityRule();
|
||||
}
|
||||
transitionData.add(new TransitionData<S, E>(source, target, state, event, period, count, actions, guard, kind, securityRule));
|
||||
transitionData.add(new TransitionData<>(source, target, state, event, period, count, actions, guard, kind, securityRule, errorAction));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
@@ -27,6 +24,9 @@ import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.security.SecurityRule.ComparisonType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Base class for transition configurers.
|
||||
*
|
||||
@@ -44,9 +44,10 @@ public abstract class AbstractTransitionConfigurer<S, E> extends
|
||||
private E event;
|
||||
private Long period;
|
||||
private Integer count;
|
||||
private final Collection<Action<S, E>> actions = new ArrayList<Action<S, E>>();
|
||||
private final Collection<Action<S, E>> actions = new ArrayList<>();
|
||||
private Guard<S, E> guard;
|
||||
private SecurityRule securityRule;
|
||||
private Action<S, E> errorAction;
|
||||
|
||||
protected S getSource() {
|
||||
return source;
|
||||
@@ -68,6 +69,10 @@ public abstract class AbstractTransitionConfigurer<S, E> extends
|
||||
return period;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return trigger count
|
||||
*/
|
||||
public Integer getCount() {
|
||||
return count;
|
||||
}
|
||||
@@ -104,6 +109,10 @@ public abstract class AbstractTransitionConfigurer<S, E> extends
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param count to set how many time the trigger will be called.
|
||||
*/
|
||||
public void setCount(Integer count) {
|
||||
this.count = count;
|
||||
}
|
||||
@@ -116,6 +125,22 @@ public abstract class AbstractTransitionConfigurer<S, E> extends
|
||||
this.guard = guard;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the Error {@link Action}
|
||||
*/
|
||||
public Action<S, E> getErrorAction() {
|
||||
return errorAction;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param errorAction the {@link Action} that will be called each time an action is gonna throw an exception.
|
||||
*/
|
||||
public void setErrorAction(Action<S, E> errorAction) {
|
||||
this.errorAction = errorAction;
|
||||
}
|
||||
|
||||
protected void setSecurityRule(String attributes, ComparisonType match) {
|
||||
if (securityRule == null) {
|
||||
securityRule = new SecurityRule();
|
||||
|
||||
@@ -39,7 +39,7 @@ public class DefaultExternalTransitionConfigurer<S, E> extends AbstractTransitio
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.addTransition(getSource(), getTarget(), getState(), getEvent(), getPeriod(), getCount(), getActions(), getGuard(), TransitionKind.EXTERNAL,
|
||||
getSecurityRule());
|
||||
getSecurityRule(), getErrorAction());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,7 +81,13 @@ public class DefaultExternalTransitionConfigurer<S, E> extends AbstractTransitio
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> action(Action<S, E> action) {
|
||||
return action(action, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> action(Action<S, E> action, Action<S, E> error) {
|
||||
addAction(action);
|
||||
setErrorAction(error);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public class DefaultInternalTransitionConfigurer<S, E> extends AbstractTransitio
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.addTransition(getSource(), getTarget(), getState(), getEvent(), getPeriod(), getCount(), getActions(), getGuard(), TransitionKind.INTERNAL,
|
||||
getSecurityRule());
|
||||
getSecurityRule(), getErrorAction());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,7 +75,13 @@ public class DefaultInternalTransitionConfigurer<S, E> extends AbstractTransitio
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> action(Action<S, E> action) {
|
||||
return action(action, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> action(Action<S, E> action, Action<S, E> error) {
|
||||
addAction(action);
|
||||
setErrorAction(error);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class DefaultLocalTransitionConfigurer<S, E> extends AbstractTransitionCo
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.addTransition(getSource(), getTarget(), getState(), getEvent(), getPeriod(), getCount(), getActions(), getGuard(), TransitionKind.LOCAL,
|
||||
getSecurityRule());
|
||||
getSecurityRule(), getErrorAction());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,7 +80,13 @@ public class DefaultLocalTransitionConfigurer<S, E> extends AbstractTransitionCo
|
||||
|
||||
@Override
|
||||
public LocalTransitionConfigurer<S, E> action(Action<S, E> action) {
|
||||
return action(action, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransitionConfigurer<S, E> action(Action<S, E> action, Action<S, E> error) {
|
||||
addAction(action);
|
||||
setErrorAction(error);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,15 @@ public interface TransitionConfigurer<T, S, E> extends
|
||||
*/
|
||||
T action(Action<S, E> action);
|
||||
|
||||
/**
|
||||
* Specify {@link Action} for this {@link Transition}.
|
||||
*
|
||||
* @param action the action
|
||||
* @param error that will be called if any unexpected exception is thrown by the action.
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
T action(Action<S, E> action, Action<S, E> error);
|
||||
|
||||
/**
|
||||
* Specify a {@link Guard} for this {@link Transition}.
|
||||
*
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.model;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A simple data object keeping transition related configs in a same place.
|
||||
*
|
||||
@@ -39,6 +39,7 @@ public class TransitionData<S, E> {
|
||||
private final Guard<S, E> guard;
|
||||
private final TransitionKind kind;
|
||||
private final SecurityRule securityRule;
|
||||
private final Action<S, E> errorAction;
|
||||
|
||||
/**
|
||||
* Instantiates a new transition data.
|
||||
@@ -48,7 +49,7 @@ public class TransitionData<S, E> {
|
||||
* @param event the event
|
||||
*/
|
||||
public TransitionData(S source, S target, E event) {
|
||||
this(source, target, null, event, null, null, null, null, TransitionKind.EXTERNAL, null);
|
||||
this(source, target, null, event, null, null, null, null, TransitionKind.EXTERNAL, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +64,7 @@ public class TransitionData<S, E> {
|
||||
*/
|
||||
public TransitionData(S source, S target, E event, Collection<Action<S, E>> actions,
|
||||
Guard<S, E> guard, TransitionKind kind) {
|
||||
this(source, target, null, event, null, null, actions, guard, kind, null);
|
||||
this(source, target, null, event, null, null, actions, guard, kind, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,7 +80,7 @@ public class TransitionData<S, E> {
|
||||
*/
|
||||
public TransitionData(S source, S target, Long period, Integer count, Collection<Action<S, E>> actions,
|
||||
Guard<S, E> guard, TransitionKind kind) {
|
||||
this(source, target, null, null, period, count, actions, guard, kind, null);
|
||||
this(source, target, null, null, period, count, actions, guard, kind, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,9 +96,10 @@ public class TransitionData<S, E> {
|
||||
* @param guard the guard
|
||||
* @param kind the kind
|
||||
* @param securityRule the security rule
|
||||
* @param errorAction the {@link Action} that will be called each time an action is gonna throw an exception.
|
||||
*/
|
||||
public TransitionData(S source, S target, S state, E event, Long period, Integer count, Collection<Action<S, E>> actions,
|
||||
Guard<S, E> guard, TransitionKind kind, SecurityRule securityRule) {
|
||||
Guard<S, E> guard, TransitionKind kind, SecurityRule securityRule, Action<S, E> errorAction) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.state = state;
|
||||
@@ -108,6 +110,7 @@ public class TransitionData<S, E> {
|
||||
this.guard = guard;
|
||||
this.kind = kind;
|
||||
this.securityRule = securityRule;
|
||||
this.errorAction = errorAction;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,4 +202,12 @@ public class TransitionData<S, E> {
|
||||
public SecurityRule getSecurityRule() {
|
||||
return securityRule;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the error {@link Action}
|
||||
*/
|
||||
public Action<S, E> getErrorAction() {
|
||||
return errorAction;
|
||||
}
|
||||
}
|
||||
@@ -15,19 +15,19 @@
|
||||
*/
|
||||
package org.springframework.statemachine.transition;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.trigger.Trigger;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public abstract class AbstractExternalTransition<S, E> extends AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
public AbstractExternalTransition(State<S, E> source, State<S, E> target, Collection<Action<S, E>> actions,
|
||||
E event, Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, target, actions, event, TransitionKind.EXTERNAL, guard, trigger, securityRule);
|
||||
E event, Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule, Action<S, E> errorAction) {
|
||||
super(source, target, actions, event, TransitionKind.EXTERNAL, guard, trigger, securityRule, errorAction);
|
||||
}
|
||||
|
||||
public AbstractExternalTransition(State<S, E> source, State<S, E> target, Collection<Action<S, E>> actions,
|
||||
|
||||
@@ -31,8 +31,8 @@ public class AbstractInternalTransition<S, E> extends AbstractTransition<S, E> i
|
||||
}
|
||||
|
||||
public AbstractInternalTransition(State<S, E> source, Collection<Action<S, E>> actions, E event, Guard<S, E> guard,
|
||||
Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, source, actions, event, TransitionKind.INTERNAL, guard, trigger, securityRule);
|
||||
Trigger<S, E> trigger, SecurityRule securityRule, Action<S, E> errorAction) {
|
||||
super(source, source, actions, event, TransitionKind.INTERNAL, guard, trigger, securityRule, errorAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package org.springframework.statemachine.transition;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.trigger.Trigger;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class AbstractLocalTransition<S, E> extends AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
public AbstractLocalTransition(State<S, E> source, State<S, E> target, Collection<Action<S, E>> actions, E event,
|
||||
@@ -31,8 +31,8 @@ public class AbstractLocalTransition<S, E> extends AbstractTransition<S, E> impl
|
||||
}
|
||||
|
||||
public AbstractLocalTransition(State<S, E> source, State<S, E> target, Collection<Action<S, E>> actions, E event,
|
||||
Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, target, actions, event, TransitionKind.LOCAL, guard, trigger, securityRule);
|
||||
Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule, Action<S, E> errorAction) {
|
||||
super(source, target, actions, event, TransitionKind.LOCAL, guard, trigger, securityRule, errorAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,18 +15,19 @@
|
||||
*/
|
||||
package org.springframework.statemachine.transition;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.action.Actions;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.trigger.Trigger;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Base implementation of a {@link Transition}.
|
||||
*
|
||||
@@ -38,12 +39,11 @@ import org.springframework.util.Assert;
|
||||
public abstract class AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
private final static Log log = LogFactory.getLog(AbstractTransition.class);
|
||||
protected final State<S, E> target;
|
||||
protected final Collection<Action<S, E>> actions;
|
||||
protected final Action<S, E> errorAction;
|
||||
|
||||
private final State<S,E> source;
|
||||
|
||||
private final State<S,E> target;
|
||||
|
||||
private final Collection<Action<S, E>> actions;
|
||||
private final State<S, E> source;
|
||||
|
||||
private final TransitionKind kind;
|
||||
|
||||
@@ -53,39 +53,57 @@ public abstract class AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
private final SecurityRule securityRule;
|
||||
|
||||
public AbstractTransition(State<S, E> source, State<S, E> target, Collection<Action<S, E>> actions, E event,
|
||||
TransitionKind kind, Guard<S, E> guard, Trigger<S, E> trigger) {
|
||||
this(source, target, actions, event, kind, guard, trigger, null);
|
||||
public AbstractTransition(State<S, E> source,
|
||||
State<S, E> target,
|
||||
Collection<Action<S, E>> actions,
|
||||
E event,
|
||||
TransitionKind kind,
|
||||
Guard<S, E> guard,
|
||||
Trigger<S, E> trigger) {
|
||||
this(source, target, actions, event, kind, guard, trigger, null, Actions.<S, E>emptyAction());
|
||||
}
|
||||
|
||||
public AbstractTransition(State<S, E> source, State<S, E> target, Collection<Action<S, E>> actions, E event,
|
||||
TransitionKind kind, Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
public AbstractTransition(State<S, E> source,
|
||||
State<S, E> target,
|
||||
Collection<Action<S, E>> actions,
|
||||
E event,
|
||||
TransitionKind kind,
|
||||
Guard<S, E> guard,
|
||||
Trigger<S, E> trigger,
|
||||
SecurityRule securityRule,
|
||||
Action<S, E> errorAction) {
|
||||
Assert.notNull(source, "Source must be set");
|
||||
Assert.notNull(kind, "Transition type must be set");
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.actions = actions;
|
||||
this.kind = kind;
|
||||
this.errorAction = errorAction == null
|
||||
? Actions.<S, E> emptyAction()
|
||||
: errorAction; this.kind = kind;
|
||||
this.guard = guard;
|
||||
this.trigger = trigger;
|
||||
this.securityRule = securityRule;
|
||||
}
|
||||
|
||||
protected AbstractTransition(State<S, E> target, Collection<Action<S, E>> actions, TransitionKind kind, Action<S, E> errorAction) {
|
||||
Assert.notNull(kind, "Transition type must be set");
|
||||
this.source = null;
|
||||
this.target = target;
|
||||
this.actions = actions;
|
||||
this.errorAction = errorAction == null
|
||||
? Actions.<S, E> emptyAction()
|
||||
: errorAction;
|
||||
this.kind = kind;
|
||||
this.guard = null;
|
||||
this.trigger = null;
|
||||
this.securityRule = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S,E> getSource() {
|
||||
public State<S, E> getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S,E> getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Action<S, E>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger<S, E> getTrigger() {
|
||||
return trigger;
|
||||
@@ -98,16 +116,14 @@ public abstract class AbstractTransition<S, E> implements Transition<S, E> {
|
||||
if (!guard.evaluate(context)) {
|
||||
return false;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
catch (Throwable t) {
|
||||
log.warn("Deny guard due to throw as GUARD should not error", t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (actions != null) {
|
||||
for (Action<S, E> action : actions) {
|
||||
action.execute(context);
|
||||
}
|
||||
}
|
||||
executeAllActions(context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -121,4 +137,44 @@ public abstract class AbstractTransition<S, E> implements Transition<S, E> {
|
||||
return securityRule;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the target {@link State}
|
||||
*/
|
||||
public State<S, E> getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return all {@link Action}
|
||||
*/
|
||||
public Collection<Action<S, E>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the {@link Action} called of any error occurred while actions are executed.
|
||||
*/
|
||||
public Action<S, E> getErrorAction() {
|
||||
return errorAction;
|
||||
}
|
||||
|
||||
protected final void executeAllActions(StateContext<S, E> context) {
|
||||
if (actions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Action<S, E> action : actions) {
|
||||
try {
|
||||
action.execute(context);
|
||||
}
|
||||
catch (Exception exception) {
|
||||
errorAction.execute(context); // notify something wrong is happening in
|
||||
// Actions execution.
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package org.springframework.statemachine.transition;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.trigger.Trigger;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class DefaultExternalTransition<S, E> extends AbstractExternalTransition<S, E> {
|
||||
|
||||
public DefaultExternalTransition(State<S, E> source, State<S, E> target, Collection<Action<S, E>> actions, E event,
|
||||
@@ -31,8 +31,8 @@ public class DefaultExternalTransition<S, E> extends AbstractExternalTransition<
|
||||
}
|
||||
|
||||
public DefaultExternalTransition(State<S, E> source, State<S, E> target, Collection<Action<S, E>> actions, E event,
|
||||
Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, target, actions, event, guard, trigger, securityRule);
|
||||
Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule, Action<S, E> errorAction) {
|
||||
super(source, target, actions, event, guard, trigger, securityRule, errorAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package org.springframework.statemachine.transition;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.trigger.Trigger;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class DefaultInternalTransition<S, E> extends AbstractInternalTransition<S, E> {
|
||||
|
||||
public DefaultInternalTransition(State<S, E> source, Collection<Action<S, E>> actions, E event, Guard<S, E> guard,
|
||||
@@ -31,8 +31,8 @@ public class DefaultInternalTransition<S, E> extends AbstractInternalTransition<
|
||||
}
|
||||
|
||||
public DefaultInternalTransition(State<S, E> source, Collection<Action<S, E>> actions, E event, Guard<S, E> guard,
|
||||
Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, actions, event, guard, trigger, securityRule);
|
||||
Trigger<S, E> trigger, SecurityRule securityRule, Action<S, E> errorAction) {
|
||||
super(source, actions, event, guard, trigger, securityRule, errorAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,14 +15,12 @@
|
||||
*/
|
||||
package org.springframework.statemachine.transition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.trigger.Trigger;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* {@link Transition} used during a state machine start.
|
||||
@@ -32,87 +30,39 @@ import org.springframework.statemachine.trigger.Trigger;
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class InitialTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
private final State<S, E> target;
|
||||
|
||||
private final Collection<Action<S, E>> actions;
|
||||
public class InitialTransition<S, E> extends AbstractTransition<S, E>
|
||||
implements Transition<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new initial transition.
|
||||
*
|
||||
* @param target the initial target state
|
||||
* @param target state.
|
||||
*/
|
||||
public InitialTransition(State<S, E> target) {
|
||||
this.target = target;
|
||||
this.actions = null;
|
||||
this(target, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new initial transition.
|
||||
*
|
||||
* @param target the initial target state
|
||||
* @param action the initial action
|
||||
* @param target state
|
||||
* @param action to be executed to succeed for this transition
|
||||
*/
|
||||
public InitialTransition(State<S, E> target, Action<S, E> action) {
|
||||
this.target = target;
|
||||
ArrayList<Action<S,E>> list = new ArrayList<Action<S, E>>();
|
||||
if (action != null) {
|
||||
list.add(action);
|
||||
}
|
||||
this.actions = list;
|
||||
this(target, action == null ? Collections.<Action<S,E>>emptyList(): Collections.singleton(action), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new initial transition.
|
||||
*
|
||||
* @param target the initial target state
|
||||
* @param actions the initial actions
|
||||
* @param target state
|
||||
* @param actions to be executed to succeed for this transition
|
||||
* @param errorAction to be executed if one of {@link #getActions()} throw an exception.
|
||||
*/
|
||||
public InitialTransition(State<S, E> target, Collection<Action<S, E>> actions) {
|
||||
this.target = target;
|
||||
this.actions = actions;
|
||||
public InitialTransition(State<S, E> target, Collection<Action<S, E>> actions, Action<S, E> errorAction) {
|
||||
super(target, actions, TransitionKind.INITIAL, errorAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transit(StateContext<S, E> context) {
|
||||
if (actions != null) {
|
||||
for (Action<S, E> action : actions) {
|
||||
action.execute(context);
|
||||
}
|
||||
}
|
||||
executeAllActions(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S, E> getSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S, E> getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Action<S, E>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger<S, E> getTrigger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransitionKind getKind() {
|
||||
return TransitionKind.INITIAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityRule getSecurityRule() {
|
||||
// initial cannot have security
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package org.springframework.statemachine.transition;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.trigger.Trigger;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* {@code Transition} is something what a state machine associates with a state
|
||||
* changes.
|
||||
@@ -63,6 +63,14 @@ public interface Transition<S, E> {
|
||||
*/
|
||||
Collection<Action<S, E>> getActions();
|
||||
|
||||
/**
|
||||
* Get The action that will be execute if one of {@link #getActions()} throw an exception.
|
||||
* This action may be usefull if you want to notify another sub system from unexpected technical error.
|
||||
*
|
||||
* @return the error {@link Action}
|
||||
*/
|
||||
Action<S, E> getErrorAction();
|
||||
|
||||
/**
|
||||
* Gets the transition trigger.
|
||||
*
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
*/
|
||||
package org.springframework.statemachine.action;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -35,6 +31,10 @@ import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for state machine actions.
|
||||
*
|
||||
@@ -54,13 +54,18 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
|
||||
TestCountAction testAction1 = ctx.getBean("testAction1", TestCountAction.class);
|
||||
TestCountAction testAction2 = ctx.getBean("testAction2", TestCountAction.class);
|
||||
TestCountAction testAction3 = ctx.getBean("testAction3", TestCountAction.class);
|
||||
TestCountAction testAction3 = ctx.getBean("testAction3", TestCountAction.class);
|
||||
TestCountAction testAction4 = ctx.getBean("testAction4", TestCountAction.class);
|
||||
TestCountAction testErrorAction = ctx.getBean("testErrorAction", TestCountAction.class);
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E2).build());
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E3).build());
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E3).build());
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E4).build());
|
||||
assertThat(testAction1.count, is(1));
|
||||
assertThat(testAction2.count, is(1));
|
||||
assertThat(testAction3.count, is(1));
|
||||
assertThat(testAction3.count, is(1));
|
||||
assertThat(testAction4.count, is(0));
|
||||
assertThat(testErrorAction.count, is(1));
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@@ -95,8 +100,9 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
.initial(TestStates.S1)
|
||||
.state(TestStates.S1)
|
||||
.state(TestStates.S2)
|
||||
.state(TestStates.S3)
|
||||
.state(TestStates.S4);
|
||||
.state(TestStates.S3)
|
||||
.state(TestStates.S4)
|
||||
.state(TestStates.S10);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,7 +124,13 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
.source(TestStates.S3)
|
||||
.target(TestStates.S4)
|
||||
.event(TestEvents.E3)
|
||||
.action(testAction3());
|
||||
.action(testAction3())
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(TestStates.S4)
|
||||
.target(TestStates.S10)
|
||||
.event(TestEvents.E4)
|
||||
.action(testAction4(), testErrorAction());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -131,8 +143,23 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
return new TestCountAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestCountAction testAction3() {
|
||||
@Bean
|
||||
public TestCountAction testAction3() {
|
||||
return new TestCountAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestCountAction testAction4() {
|
||||
return new TestCountAction() {
|
||||
@Override
|
||||
public void execute(StateContext<TestStates, TestEvents> context) {
|
||||
throw new RuntimeException("Fake Error");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestCountAction testErrorAction() {
|
||||
return new TestCountAction();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,16 +15,6 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.model;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
@@ -40,6 +30,12 @@ import org.springframework.statemachine.listener.StateMachineListener;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class StateMachineModelTests {
|
||||
|
||||
@Test
|
||||
@@ -72,7 +68,7 @@ public class StateMachineModelTests {
|
||||
|
||||
|
||||
Collection<TransitionData<String, String>> transitions = new ArrayList<>();
|
||||
TransitionData<String, String> transitionData1 = new TransitionData<String, String>("S1", "S2", null, "E1", null, null, null, null, TransitionKind.EXTERNAL, null);
|
||||
TransitionData<String, String> transitionData1 = new TransitionData<String, String>("S1", "S2", null, "E1", null, null, null, null, TransitionKind.EXTERNAL, null, null);
|
||||
transitions.add(transitionData1);
|
||||
Map<String, List<ChoiceData<String, String>>> choices = new HashMap<>();
|
||||
Map<String, List<JunctionData<String, String>>> junctions = new HashMap<>();
|
||||
|
||||
@@ -15,15 +15,6 @@
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
@@ -36,6 +27,7 @@ import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.access.StateMachineAccessor;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.action.Actions;
|
||||
import org.springframework.statemachine.listener.StateMachineListener;
|
||||
import org.springframework.statemachine.security.SecurityRule;
|
||||
import org.springframework.statemachine.state.EnumState;
|
||||
@@ -44,6 +36,11 @@ import org.springframework.statemachine.transition.Transition;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
import org.springframework.statemachine.trigger.Trigger;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class StateContextExpressionMethodsTests {
|
||||
|
||||
@Test
|
||||
@@ -133,6 +130,10 @@ public class StateContextExpressionMethodsTests {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action<SpelStates, SpelEvents> getErrorAction() {
|
||||
return Actions.emptyAction();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MockStatemachine implements StateMachine<SpelStates, SpelEvents> {
|
||||
|
||||
Reference in New Issue
Block a user