Transition error action not used per defined action
- Revert some previous changes order to define transition error action logic in a different place. Now basically wrapping try/catch in a dedicated action order to have separate error action per action as is expected by a config SPI. - Added some tests. - Added docs for transition error actions. - Relates to #238 - Fixes #259
This commit is contained in:
@@ -160,6 +160,7 @@ expression based guard is a _SpelExpressionGuard_. This was attached to
|
||||
transition between states `S2` and `S3`. Both guard in above sample
|
||||
always evaluate to true.
|
||||
|
||||
[[statemachine-config-actions]]
|
||||
=== Configuring Actions
|
||||
Actions can be defined to be executed with transitions and states
|
||||
itself. Action is always executed as a result of a transition which
|
||||
@@ -220,6 +221,27 @@ wrapped within a `Runnable` which may get cancelled via
|
||||
action, you need to be able to catch `InterruptedException` which is
|
||||
raised if task is cancelled.
|
||||
|
||||
[[statemachine-config-actions-errorhandling]]
|
||||
==== Transition Action Error Handling
|
||||
|
||||
User can always catch exceptions manually but with actions defined for
|
||||
transitions it is possible to define error action which is called if
|
||||
exception is reased. Exception is then available from a `StateContext`
|
||||
passed to that action.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippetEC]
|
||||
----
|
||||
|
||||
Similar logic can be done manually for every action if needed.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippetED]
|
||||
----
|
||||
|
||||
|
||||
=== Configuring Pseudo States
|
||||
|
||||
_Pseudo state_ configuration is usually done by configuring states and
|
||||
@@ -1583,6 +1605,12 @@ recognize only `StateMachineEvent` instances.
|
||||
include::samples/DocsConfigurationSampleTests.java[tags=snippet4]
|
||||
----
|
||||
|
||||
[TIP]
|
||||
====
|
||||
Actions defined for transitions also have their own error handling
|
||||
logic <<statemachine-config-actions-errorhandling>>.
|
||||
====
|
||||
|
||||
[[sm-persist]]
|
||||
== Persisting State Machine
|
||||
Traditionally an instance of a state machine is used as is within a
|
||||
|
||||
@@ -30,5 +30,5 @@ _UML_ support and integrations with external config repositories.
|
||||
* New _Repository_ abstraction keeping machine configuration in an
|
||||
external repository <<sm-repository>>
|
||||
* New support for state actions. <<state-actions>>
|
||||
* New error action concepts.
|
||||
* New transition error action concepts. <<statemachine-config-actions-errorhandling>>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 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,9 +17,13 @@
|
||||
package org.springframework.statemachine.action;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.support.DefaultStateContext;
|
||||
|
||||
/**
|
||||
* Action Utilities.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public final class Actions {
|
||||
|
||||
@@ -28,9 +32,10 @@ public final class Actions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a noop {@link Action}.
|
||||
*
|
||||
* @param <S> represents states Class
|
||||
* @param <E> represents event Class
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
* @return an empty (Noop) Action.
|
||||
*/
|
||||
public static <S, E> Action<S, E> emptyAction() {
|
||||
@@ -41,4 +46,35 @@ public final class Actions {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a erro calling action {@link Action}.
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
* @param action the action
|
||||
* @param errorAction the error action
|
||||
* @return the error calling action
|
||||
*/
|
||||
public static <S, E> Action<S, E> errorCallingAction(final Action<S, E> action, final Action<S, E> errorAction) {
|
||||
return new Action<S, E>() {
|
||||
@Override
|
||||
public void execute(final StateContext<S, E> context) {
|
||||
try {
|
||||
action.execute(context);
|
||||
}
|
||||
catch (Exception exception) {
|
||||
// notify something wrong is happening in actions execution.
|
||||
try {
|
||||
errorAction.execute(new DefaultStateContext<>(context.getStage(), context.getMessage(), context.getMessageHeaders(),
|
||||
context.getExtendedState(), context.getTransition(), context.getStateMachine(), context.getSource(),
|
||||
context.getTarget(), context.getSources(), context.getTargets(), exception));
|
||||
} catch (Exception e) {
|
||||
// not interested
|
||||
}
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,7 +735,7 @@ 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.getErrorAction());
|
||||
transitionData.getSecurityRule());
|
||||
transitions.add(transition);
|
||||
|
||||
} else if (transitionData.getKind() == TransitionKind.LOCAL) {
|
||||
@@ -745,12 +745,12 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
}
|
||||
DefaultLocalTransition<S, E> transition = new DefaultLocalTransition<S, E>(stateMap.get(source),
|
||||
stateMap.get(target), transitionData.getActions(), event, transitionData.getGuard(), trigger,
|
||||
transitionData.getSecurityRule(), transitionData.getErrorAction());
|
||||
transitionData.getSecurityRule());
|
||||
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.getErrorAction());
|
||||
transitionData.getSecurityRule());
|
||||
transitions.add(transition);
|
||||
}
|
||||
}
|
||||
@@ -764,7 +764,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, null);
|
||||
source, target, null, null, null, null, null);
|
||||
transitions.add(transition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,17 +174,16 @@ 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, Action<S, E> errorAction) {
|
||||
Guard<S, E> guard, TransitionKind kind, SecurityRule securityRule) {
|
||||
// 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<>(source, target, state, event, period, count, actions, guard, kind, securityRule, errorAction));
|
||||
transitionData.add(new TransitionData<>(source, target, state, event, period, count, actions, guard, kind, securityRule));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.action.Actions;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
@@ -47,7 +48,6 @@ public abstract class AbstractTransitionConfigurer<S, E> extends
|
||||
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;
|
||||
@@ -118,29 +118,17 @@ public abstract class AbstractTransitionConfigurer<S, E> extends
|
||||
}
|
||||
|
||||
protected void addAction(Action<S, E> action) {
|
||||
this.actions.add(action);
|
||||
addAction(action, null);
|
||||
}
|
||||
|
||||
protected void addAction(Action<S, E> action, Action<S, E> error) {
|
||||
this.actions.add(error != null ? Actions.errorCallingAction(action, error) : action);
|
||||
}
|
||||
|
||||
protected void setGuard(Guard<S, E> guard) {
|
||||
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(), getErrorAction());
|
||||
getSecurityRule());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,8 +86,7 @@ public class DefaultExternalTransitionConfigurer<S, E> extends AbstractTransitio
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> action(Action<S, E> action, Action<S, E> error) {
|
||||
addAction(action);
|
||||
setErrorAction(error);
|
||||
addAction(action, 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(), getErrorAction());
|
||||
getSecurityRule());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,8 +80,7 @@ public class DefaultInternalTransitionConfigurer<S, E> extends AbstractTransitio
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> action(Action<S, E> action, Action<S, E> error) {
|
||||
addAction(action);
|
||||
setErrorAction(error);
|
||||
addAction(action, 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(), getErrorAction());
|
||||
getSecurityRule());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,8 +85,7 @@ public class DefaultLocalTransitionConfigurer<S, E> extends AbstractTransitionCo
|
||||
|
||||
@Override
|
||||
public LocalTransitionConfigurer<S, E> action(Action<S, E> action, Action<S, E> error) {
|
||||
addAction(action);
|
||||
setErrorAction(error);
|
||||
addAction(action, error);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -87,7 +87,7 @@ public interface TransitionConfigurer<T, S, E> extends
|
||||
* 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.
|
||||
* @param error action 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);
|
||||
|
||||
@@ -39,7 +39,6 @@ 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.
|
||||
@@ -49,7 +48,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, null);
|
||||
this(source, target, null, event, null, null, null, null, TransitionKind.EXTERNAL, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +63,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, null);
|
||||
this(source, target, null, event, null, null, actions, guard, kind, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,7 +79,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, null);
|
||||
this(source, target, null, null, period, count, actions, guard, kind, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,10 +95,9 @@ 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, Action<S, E> errorAction) {
|
||||
Guard<S, E> guard, TransitionKind kind, SecurityRule securityRule) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.state = state;
|
||||
@@ -110,7 +108,6 @@ public class TransitionData<S, E> {
|
||||
this.guard = guard;
|
||||
this.kind = kind;
|
||||
this.securityRule = securityRule;
|
||||
this.errorAction = errorAction;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,12 +199,4 @@ public class TransitionData<S, E> {
|
||||
public SecurityRule getSecurityRule() {
|
||||
return securityRule;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the error {@link Action}
|
||||
*/
|
||||
public Action<S, E> getErrorAction() {
|
||||
return errorAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,14 +25,34 @@ import java.util.Collection;
|
||||
|
||||
public abstract class AbstractExternalTransition<S, E> extends AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract external transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
* @param securityRule the security rule
|
||||
*/
|
||||
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, Action<S, E> errorAction) {
|
||||
super(source, target, actions, event, TransitionKind.EXTERNAL, guard, trigger, securityRule, errorAction);
|
||||
E event, Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, target, actions, event, TransitionKind.EXTERNAL, guard, trigger, securityRule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract external transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
*/
|
||||
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) {
|
||||
super(source, target, actions, event, TransitionKind.EXTERNAL, guard, trigger);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,14 +25,32 @@ import org.springframework.statemachine.trigger.Trigger;
|
||||
|
||||
public class AbstractInternalTransition<S, E> extends AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract internal transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
*/
|
||||
public AbstractInternalTransition(State<S, E> source, Collection<Action<S, E>> actions, E event, Guard<S, E> guard,
|
||||
Trigger<S, E> trigger) {
|
||||
super(source, source, actions, event, TransitionKind.INTERNAL, guard, trigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract internal transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
* @param securityRule the security rule
|
||||
*/
|
||||
public AbstractInternalTransition(State<S, E> source, Collection<Action<S, E>> actions, E event, Guard<S, E> guard,
|
||||
Trigger<S, E> trigger, SecurityRule securityRule, Action<S, E> errorAction) {
|
||||
super(source, source, actions, event, TransitionKind.INTERNAL, guard, trigger, securityRule, errorAction);
|
||||
Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, source, actions, event, TransitionKind.INTERNAL, guard, trigger, securityRule);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,14 +25,34 @@ import java.util.Collection;
|
||||
|
||||
public class AbstractLocalTransition<S, E> extends AbstractTransition<S, E> implements Transition<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract local transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
*/
|
||||
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) {
|
||||
super(source, target, actions, event, TransitionKind.LOCAL, guard, trigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract local transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
* @param securityRule the security rule
|
||||
*/
|
||||
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, Action<S, E> errorAction) {
|
||||
super(source, target, actions, event, TransitionKind.LOCAL, guard, trigger, securityRule, errorAction);
|
||||
Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, target, actions, event, TransitionKind.LOCAL, guard, trigger, securityRule);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,19 +15,18 @@
|
||||
*/
|
||||
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}.
|
||||
*
|
||||
@@ -41,64 +40,52 @@ 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 TransitionKind kind;
|
||||
|
||||
private final Guard<S, E> guard;
|
||||
|
||||
private final Trigger<S, E> trigger;
|
||||
|
||||
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, Actions.<S, E>emptyAction());
|
||||
/**
|
||||
* Instantiates a new abstract transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param kind the kind
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
*/
|
||||
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,
|
||||
SecurityRule securityRule,
|
||||
Action<S, E> errorAction) {
|
||||
Assert.notNull(source, "Source must be set");
|
||||
/**
|
||||
* Instantiates a new abstract transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param kind the kind
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
* @param securityRule the security rule
|
||||
*/
|
||||
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) {
|
||||
Assert.notNull(kind, "Transition type must be set");
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.actions = actions;
|
||||
this.errorAction = errorAction == null
|
||||
? Actions.<S, E> emptyAction()
|
||||
: errorAction; this.kind = kind;
|
||||
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() {
|
||||
return source;
|
||||
@@ -123,7 +110,6 @@ public abstract class AbstractTransition<S, E> implements Transition<S, E> {
|
||||
}
|
||||
}
|
||||
executeAllActions(context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -137,44 +123,23 @@ public abstract class AbstractTransition<S, E> implements Transition<S, E> {
|
||||
return securityRule;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the target {@link State}
|
||||
*/
|
||||
@Override
|
||||
public State<S, E> getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return all {@link Action}
|
||||
*/
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
action.execute(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,14 +25,34 @@ import java.util.Collection;
|
||||
|
||||
public class DefaultExternalTransition<S, E> extends AbstractExternalTransition<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new default external transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
*/
|
||||
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) {
|
||||
super(source, target, actions, event, guard, trigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new default external transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
* @param securityRule the security rule
|
||||
*/
|
||||
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, Action<S, E> errorAction) {
|
||||
super(source, target, actions, event, guard, trigger, securityRule, errorAction);
|
||||
Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, target, actions, event, guard, trigger, securityRule);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,14 +25,32 @@ import java.util.Collection;
|
||||
|
||||
public class DefaultInternalTransition<S, E> extends AbstractInternalTransition<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new default internal transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
*/
|
||||
public DefaultInternalTransition(State<S, E> source, Collection<Action<S, E>> actions, E event, Guard<S, E> guard,
|
||||
Trigger<S, E> trigger) {
|
||||
super(source, actions, event, guard, trigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new default internal transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
* @param securityRule the security rule
|
||||
*/
|
||||
public DefaultInternalTransition(State<S, E> source, Collection<Action<S, E>> actions, E event, Guard<S, E> guard,
|
||||
Trigger<S, E> trigger, SecurityRule securityRule, Action<S, E> errorAction) {
|
||||
super(source, actions, event, guard, trigger, securityRule, errorAction);
|
||||
Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, actions, event, guard, trigger, securityRule);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,14 +25,35 @@ import org.springframework.statemachine.trigger.Trigger;
|
||||
|
||||
public class DefaultLocalTransition<S, E> extends AbstractLocalTransition<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new default local transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
*/
|
||||
public DefaultLocalTransition(State<S, E> source, State<S, E> target, Collection<Action<S, E>> actions, E event, Guard<S, E> guard,
|
||||
Trigger<S, E> trigger) {
|
||||
super(source, target, actions, event, guard, trigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new default local transition.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
* @param event the event
|
||||
* @param guard the guard
|
||||
* @param trigger the trigger
|
||||
* @param securityRule the security rule
|
||||
*/
|
||||
public DefaultLocalTransition(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, Action<S, E> errorAction) {
|
||||
super(source, target, actions, event, guard, trigger, securityRule, errorAction);
|
||||
Guard<S, E> guard, Trigger<S, E> trigger, SecurityRule securityRule) {
|
||||
super(source, target, actions, event, guard, trigger, securityRule);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,30 +34,32 @@ public class InitialTransition<S, E> extends AbstractTransition<S, E>
|
||||
implements Transition<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new initial transition.
|
||||
*
|
||||
* @param target state.
|
||||
* @param target the target
|
||||
*/
|
||||
public InitialTransition(State<S, E> target) {
|
||||
this(target, null);
|
||||
super(null, target, null, null, TransitionKind.INITIAL, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new initial transition.
|
||||
*
|
||||
* @param target state
|
||||
* @param action to be executed to succeed for this transition
|
||||
* @param target the target
|
||||
* @param action the action
|
||||
*/
|
||||
public InitialTransition(State<S, E> target, Action<S, E> action) {
|
||||
this(target, action == null ? Collections.<Action<S,E>>emptyList(): Collections.singleton(action), null);
|
||||
super(null, target, action != null ? Collections.singleton(action) : null, null, TransitionKind.INITIAL, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new initial transition.
|
||||
*
|
||||
* @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.
|
||||
* @param target the target
|
||||
* @param actions the actions
|
||||
*/
|
||||
public InitialTransition(State<S, E> target, Collection<Action<S, E>> actions, Action<S, E> errorAction) {
|
||||
super(target, actions, TransitionKind.INITIAL, errorAction);
|
||||
public InitialTransition(State<S, E> target, Collection<Action<S, E>> actions) {
|
||||
super(null, target, actions, null, TransitionKind.INITIAL, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -63,14 +63,6 @@ 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.
|
||||
*
|
||||
@@ -91,5 +83,4 @@ public interface Transition<S, E> {
|
||||
* @return the security rule
|
||||
*/
|
||||
SecurityRule getSecurityRule();
|
||||
|
||||
}
|
||||
|
||||
@@ -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,12 @@
|
||||
*/
|
||||
package org.springframework.statemachine.action;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
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;
|
||||
@@ -31,10 +37,6 @@ 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,18 +56,34 @@ 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 testAction4 = ctx.getBean("testAction4", TestCountAction.class);
|
||||
TestCountAction testErrorAction = ctx.getBean("testErrorAction", TestCountAction.class);
|
||||
TestCountAction testAction3 = ctx.getBean("testAction3", 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.E4).build());
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E3).build());
|
||||
assertThat(testAction1.count, is(1));
|
||||
assertThat(testAction2.count, is(1));
|
||||
assertThat(testAction3.count, is(1));
|
||||
assertThat(testAction4.count, is(0));
|
||||
assertThat(testErrorAction.count, is(1));
|
||||
assertThat(testAction3.count, is(1));
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Test
|
||||
public void testTransitionActionErrors() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config2.class);
|
||||
assertTrue(ctx.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE));
|
||||
StateMachine<TestStates,TestEvents> machine =
|
||||
ctx.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, StateMachine.class);
|
||||
machine.start();
|
||||
|
||||
TestCountAction testAction1 = ctx.getBean("testAction1", TestCountAction.class);
|
||||
TestCountAction testErrorAction = ctx.getBean("testErrorAction", TestCountAction.class);
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
|
||||
assertThat(testAction1.count, is(1));
|
||||
assertThat(testErrorAction.count, is(1));
|
||||
assertThat(testErrorAction.context, notNullValue());
|
||||
assertThat(testErrorAction.context.getException(), notNullValue());
|
||||
assertThat(testErrorAction.context.getException(), instanceOf(RuntimeException.class));
|
||||
assertThat(testErrorAction.context.getException().getMessage(), is("Fake Error"));
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@@ -77,6 +95,7 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
private static class TestCountAction implements Action<TestStates, TestEvents> {
|
||||
|
||||
int count = 0;
|
||||
StateContext<TestStates, TestEvents> context;
|
||||
|
||||
public TestCountAction() {
|
||||
count = 0;
|
||||
@@ -84,6 +103,7 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<TestStates, TestEvents> context) {
|
||||
this.context = context;
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -100,9 +120,8 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
.initial(TestStates.S1)
|
||||
.state(TestStates.S1)
|
||||
.state(TestStates.S2)
|
||||
.state(TestStates.S3)
|
||||
.state(TestStates.S4)
|
||||
.state(TestStates.S10);
|
||||
.state(TestStates.S3)
|
||||
.state(TestStates.S4);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,13 +143,7 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
.source(TestStates.S3)
|
||||
.target(TestStates.S4)
|
||||
.event(TestEvents.E3)
|
||||
.action(testAction3())
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(TestStates.S4)
|
||||
.target(TestStates.S10)
|
||||
.event(TestEvents.E4)
|
||||
.action(testAction4(), testErrorAction());
|
||||
.action(testAction3());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -143,22 +156,52 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
return new TestCountAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestCountAction testAction3() {
|
||||
return new TestCountAction();
|
||||
}
|
||||
@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 TaskExecutor taskExecutor() {
|
||||
return new SyncTaskExecutor();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class Config2 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(TestStates.S1)
|
||||
.state(TestStates.S1)
|
||||
.state(TestStates.S2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(TestStates.S1)
|
||||
.target(TestStates.S2)
|
||||
.event(TestEvents.E1)
|
||||
.action(testAction1(), testErrorAction());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestCountAction testAction1() {
|
||||
return new TestCountAction() {
|
||||
@Override
|
||||
public void execute(StateContext<TestStates, TestEvents> context) {
|
||||
super.execute(context);
|
||||
throw new RuntimeException("Fake Error");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestCountAction testErrorAction() {
|
||||
return new TestCountAction();
|
||||
}
|
||||
@@ -169,5 +212,4 @@ public class ActionTests extends AbstractStateMachineTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -68,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, null);
|
||||
TransitionData<String, String> transitionData1 = new TransitionData<String, String>("S1", "S2", null, "E1", null, null, null, null, TransitionKind.EXTERNAL, null);
|
||||
transitions.add(transitionData1);
|
||||
Map<String, List<ChoiceData<String, String>>> choices = new HashMap<>();
|
||||
Map<String, List<JunctionData<String, String>>> junctions = new HashMap<>();
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.access.StateMachineAccess;
|
||||
import org.springframework.statemachine.access.StateMachineFunction;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.action.Actions;
|
||||
import org.springframework.statemachine.action.SpelExpressionAction;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
@@ -265,6 +266,94 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests {
|
||||
}
|
||||
// end::snippetEB[]
|
||||
|
||||
// tag::snippetEC[]
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public class Config53
|
||||
extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
|
||||
throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(States.S1)
|
||||
.target(States.S2)
|
||||
.event(Events.E1)
|
||||
.action(action(), errorAction());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<States, Events> action() {
|
||||
return new Action<States, Events>() {
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<States, Events> context) {
|
||||
throw new RuntimeException("MyError");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<States, Events> errorAction() {
|
||||
return new Action<States, Events>() {
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<States, Events> context) {
|
||||
// RuntimeException("MyError") added to context
|
||||
Exception exception = context.getException();
|
||||
exception.getMessage();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
// end::snippetEC[]
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public class Config54
|
||||
extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
// tag::snippetED[]
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
|
||||
throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(States.S1)
|
||||
.target(States.S2)
|
||||
.event(Events.E1)
|
||||
.action(Actions.errorCallingAction(action(), errorAction()));
|
||||
}
|
||||
// end::snippetED[]
|
||||
|
||||
@Bean
|
||||
public Action<States, Events> action() {
|
||||
return new Action<States, Events>() {
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<States, Events> context) {
|
||||
throw new RuntimeException("MyError");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<States, Events> errorAction() {
|
||||
return new Action<States, Events>() {
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<States, Events> context) {
|
||||
// RuntimeException("MyError") added to context
|
||||
Exception exception = context.getException();
|
||||
exception.getMessage();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// tag::snippetFA[]
|
||||
@Configuration
|
||||
@EnableStateMachineFactory
|
||||
|
||||
@@ -15,6 +15,15 @@
|
||||
*/
|
||||
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;
|
||||
@@ -27,7 +36,6 @@ 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;
|
||||
@@ -36,11 +44,6 @@ 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
|
||||
@@ -129,11 +132,6 @@ public class StateContextExpressionMethodsTests {
|
||||
public SecurityRule getSecurityRule() {
|
||||
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