Support actions with transition via choice/junction pseudostate
- Adding support for javaconfig/uml to define actions for transitions leading out from a choice or junction states. - Support for action for incoming transition is already implemented as it is defined as normal transition. - Fixes #108
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -653,7 +653,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
if (holder.getState() == null) {
|
||||
holderMap.put(c.getTarget(), holder);
|
||||
}
|
||||
choices.add(new ChoiceStateData<S, E>(holder, c.getGuard()));
|
||||
choices.add(new ChoiceStateData<S, E>(holder, c.getGuard(), c.getActions()));
|
||||
}
|
||||
PseudoState<S, E> pseudoState = new ChoicePseudoState<S, E>(choices);
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
@@ -669,7 +669,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
if (holder.getState() == null) {
|
||||
holderMap.put(c.getTarget(), holder);
|
||||
}
|
||||
junctions.add(new JunctionStateData<S, E>(holder, c.getGuard()));
|
||||
junctions.add(new JunctionStateData<S, E>(holder, c.getGuard(), c.getActions()));
|
||||
}
|
||||
PseudoState<S, E> pseudoState = new JunctionPseudoState<S, E>(junctions);
|
||||
state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
@@ -51,6 +52,35 @@ public interface ChoiceTransitionConfigurer<S, E>
|
||||
*/
|
||||
ChoiceTransitionConfigurer<S, E> first(S target, Guard<S, E> guard);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a first choice associating an
|
||||
* {@link Action} to outgoing vertex. This must be set.
|
||||
* <p>
|
||||
* In normal if/else if/else this would represent if.
|
||||
* </p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param guard the guard for this choice
|
||||
* @param action the action
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
ChoiceTransitionConfigurer<S, E> first(S target, Guard<S, E> guard, Action<S, E> action);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a first choice associating an
|
||||
* {@link Action} to outgoing vertex. This must be set.
|
||||
* <p>
|
||||
* In normal if/else if/else this would represent if.
|
||||
* </p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param guard the guard for this choice
|
||||
* @param action the action
|
||||
* @param error action that will be called if any unexpected exception is thrown by the action.
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
ChoiceTransitionConfigurer<S, E> first(S target, Guard<S, E> guard, Action<S, E> action, Action<S, E> error);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a then choice.
|
||||
* This is optional. Multiple thens will preserve order.
|
||||
@@ -62,6 +92,33 @@ public interface ChoiceTransitionConfigurer<S, E>
|
||||
*/
|
||||
ChoiceTransitionConfigurer<S, E> then(S target, Guard<S, E> guard);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a then choice associating an
|
||||
* {@link Action} to outgoing vertex. This is optional. Multiple thens
|
||||
* will preserve order.
|
||||
* <p>In normal if/else if/else this would represent else if.</p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param guard the guard for this choice
|
||||
* @param action the action
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
ChoiceTransitionConfigurer<S, E> then(S target, Guard<S, E> guard, Action<S, E> action);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a then choice associating an
|
||||
* {@link Action} to outgoing vertex. This is optional. Multiple thens
|
||||
* will preserve order.
|
||||
* <p>In normal if/else if/else this would represent else if.</p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param guard the guard for this choice
|
||||
* @param action the action
|
||||
* @param error action that will be called if any unexpected exception is thrown by the action.
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
ChoiceTransitionConfigurer<S, E> then(S target, Guard<S, E> guard, Action<S, E> action, Action<S, E> error);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a last choice.
|
||||
* This must be set.
|
||||
@@ -72,4 +129,26 @@ public interface ChoiceTransitionConfigurer<S, E>
|
||||
*/
|
||||
ChoiceTransitionConfigurer<S, E> last(S target);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a last choice associating an
|
||||
* {@link Action} to outgoing vertex. This must be set.
|
||||
* <p>In normal if/else if/else this would represent else.</p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param action the action
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
ChoiceTransitionConfigurer<S, E> last(S target, Action<S, E> action);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a last choice associating an
|
||||
* {@link Action} to outgoing vertex. This must be set.
|
||||
* <p>In normal if/else if/else this would represent else.</p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param action the action
|
||||
* @param error action that will be called if any unexpected exception is thrown by the action.
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
ChoiceTransitionConfigurer<S, E> last(S target, Action<S, E> action, Action<S, E> error);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -16,8 +16,11 @@
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
@@ -63,20 +66,61 @@ public class DefaultChoiceTransitionConfigurer<S, E>
|
||||
|
||||
@Override
|
||||
public ChoiceTransitionConfigurer<S, E> first(S target, Guard<S, E> guard) {
|
||||
this.first = new ChoiceData<S, E>(source, target, guard);
|
||||
return first(target, guard, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChoiceTransitionConfigurer<S, E> first(S target, Guard<S, E> guard, Action<S, E> action) {
|
||||
return first(target, guard, action, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChoiceTransitionConfigurer<S, E> first(S target, Guard<S, E> guard, Action<S, E> action, Action<S, E> error) {
|
||||
Collection<Action<S, E>> actions = new ArrayList<>();
|
||||
if (action != null) {
|
||||
actions.add(error != null ? Actions.errorCallingAction(action, error) : action);
|
||||
}
|
||||
this.first = new ChoiceData<S, E>(source, target, guard, actions);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChoiceTransitionConfigurer<S, E> then(S target, Guard<S, E> guard) {
|
||||
thens.add(new ChoiceData<S, E>(source, target, guard));
|
||||
return then(target, guard, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChoiceTransitionConfigurer<S, E> then(S target, Guard<S, E> guard, Action<S, E> action) {
|
||||
return then(target, guard, action, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChoiceTransitionConfigurer<S, E> then(S target, Guard<S, E> guard, Action<S, E> action, Action<S, E> error) {
|
||||
Collection<Action<S, E>> actions = new ArrayList<>();
|
||||
if (action != null) {
|
||||
actions.add(error != null ? Actions.errorCallingAction(action, error) : action);
|
||||
}
|
||||
thens.add(new ChoiceData<S, E>(source, target, guard, actions));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChoiceTransitionConfigurer<S, E> last(S target) {
|
||||
this.last = new ChoiceData<S, E>(source, target, null);
|
||||
return this;
|
||||
return last(target, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChoiceTransitionConfigurer<S, E> last(S target, Action<S, E> action) {
|
||||
return last(target, action, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChoiceTransitionConfigurer<S, E> last(S target, Action<S, E> action, Action<S, E> error) {
|
||||
Collection<Action<S, E>> actions = new ArrayList<>();
|
||||
if (action != null) {
|
||||
actions.add(error != null ? Actions.errorCallingAction(action, error) : action);
|
||||
}
|
||||
this.last = new ChoiceData<S, E>(source, target, null, actions);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 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.
|
||||
@@ -16,8 +16,11 @@
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
@@ -44,15 +47,15 @@ public class DefaultJunctionTransitionConfigurer<S, E>
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
List<JunctionData<S, E>> Junctions = new ArrayList<JunctionData<S, E>>();
|
||||
List<JunctionData<S, E>> junctions = new ArrayList<JunctionData<S, E>>();
|
||||
if (first != null) {
|
||||
Junctions.add(first);
|
||||
junctions.add(first);
|
||||
}
|
||||
Junctions.addAll(thens);
|
||||
junctions.addAll(thens);
|
||||
if (last != null) {
|
||||
Junctions.add(last);
|
||||
junctions.add(last);
|
||||
}
|
||||
builder.addJunction(source, Junctions);
|
||||
builder.addJunction(source, junctions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,20 +66,61 @@ public class DefaultJunctionTransitionConfigurer<S, E>
|
||||
|
||||
@Override
|
||||
public JunctionTransitionConfigurer<S, E> first(S target, Guard<S, E> guard) {
|
||||
this.first = new JunctionData<S, E>(source, target, guard);
|
||||
return first(target, guard, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JunctionTransitionConfigurer<S, E> first(S target, Guard<S, E> guard, Action<S, E> action) {
|
||||
return first(target, guard, action, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JunctionTransitionConfigurer<S, E> first(S target, Guard<S, E> guard, Action<S, E> action, Action<S, E> error) {
|
||||
Collection<Action<S, E>> actions = new ArrayList<>();
|
||||
if (action != null) {
|
||||
actions.add(error != null ? Actions.errorCallingAction(action, error) : action);
|
||||
}
|
||||
this.first = new JunctionData<S, E>(source, target, guard, actions);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JunctionTransitionConfigurer<S, E> then(S target, Guard<S, E> guard) {
|
||||
thens.add(new JunctionData<S, E>(source, target, guard));
|
||||
return then(target, guard, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JunctionTransitionConfigurer<S, E> then(S target, Guard<S, E> guard, Action<S, E> action) {
|
||||
return then(target, guard, action, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JunctionTransitionConfigurer<S, E> then(S target, Guard<S, E> guard, Action<S, E> action, Action<S, E> error) {
|
||||
Collection<Action<S, E>> actions = new ArrayList<>();
|
||||
if (action != null) {
|
||||
actions.add(error != null ? Actions.errorCallingAction(action, error) : action);
|
||||
}
|
||||
thens.add(new JunctionData<S, E>(source, target, guard, actions));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JunctionTransitionConfigurer<S, E> last(S target) {
|
||||
this.last = new JunctionData<S, E>(source, target, null);
|
||||
return this;
|
||||
return last(target, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JunctionTransitionConfigurer<S, E> last(S target, Action<S, E> action) {
|
||||
return last(target, action, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JunctionTransitionConfigurer<S, E> last(S target, Action<S, E> action, Action<S, E> error) {
|
||||
Collection<Action<S, E>> actions = new ArrayList<>();
|
||||
if (action != null) {
|
||||
actions.add(error != null ? Actions.errorCallingAction(action, error) : action);
|
||||
}
|
||||
this.last = new JunctionData<S, E>(source, target, null, actions);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 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,7 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
@@ -51,6 +52,35 @@ public interface JunctionTransitionConfigurer<S, E>
|
||||
*/
|
||||
JunctionTransitionConfigurer<S, E> first(S target, Guard<S, E> guard);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a first choice associating an
|
||||
* {@link Action} to outgoing vertex. This must be set.
|
||||
* <p>
|
||||
* In normal if/else if/else this would represent if.
|
||||
* </p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param guard the guard for this choice
|
||||
* @param action the action
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
JunctionTransitionConfigurer<S, E> first(S target, Guard<S, E> guard, Action<S, E> action);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a first choice associating an
|
||||
* {@link Action} to outgoing vertex. This must be set.
|
||||
* <p>
|
||||
* In normal if/else if/else this would represent if.
|
||||
* </p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param guard the guard for this choice
|
||||
* @param action the action
|
||||
* @param error action that will be called if any unexpected exception is thrown by the action.
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
JunctionTransitionConfigurer<S, E> first(S target, Guard<S, E> guard, Action<S, E> action, Action<S, E> error);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a then choice.
|
||||
* This is optional. Multiple thens will preserve order.
|
||||
@@ -62,6 +92,33 @@ public interface JunctionTransitionConfigurer<S, E>
|
||||
*/
|
||||
JunctionTransitionConfigurer<S, E> then(S target, Guard<S, E> guard);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a then choice associating an
|
||||
* {@link Action} to outgoing vertex. This is optional. Multiple thens
|
||||
* will preserve order.
|
||||
* <p>In normal if/else if/else this would represent else if.</p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param guard the guard for this choice
|
||||
* @param action the action
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
JunctionTransitionConfigurer<S, E> then(S target, Guard<S, E> guard, Action<S, E> action);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a then choice associating an
|
||||
* {@link Action} to outgoing vertex. This is optional. Multiple thens
|
||||
* will preserve order.
|
||||
* <p>In normal if/else if/else this would represent else if.</p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param guard the guard for this choice
|
||||
* @param action the action
|
||||
* @param error action that will be called if any unexpected exception is thrown by the action.
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
JunctionTransitionConfigurer<S, E> then(S target, Guard<S, E> guard, Action<S, E> action, Action<S, E> error);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a last choice.
|
||||
* This must be set.
|
||||
@@ -72,4 +129,27 @@ public interface JunctionTransitionConfigurer<S, E>
|
||||
*/
|
||||
JunctionTransitionConfigurer<S, E> last(S target);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a last choice associating an
|
||||
* {@link Action} to outgoing vertex. This must be set.
|
||||
* <p>In normal if/else if/else this would represent else.</p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param action the action
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
JunctionTransitionConfigurer<S, E> last(S target, Action<S, E> action);
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} as a last choice associating an
|
||||
* {@link Action} to outgoing vertex. This must be set.
|
||||
* <p>In normal if/else if/else this would represent else.</p>
|
||||
*
|
||||
* @param target the target state
|
||||
* @param action the action
|
||||
* @param error action that will be called if any unexpected exception is thrown by the action.
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
JunctionTransitionConfigurer<S, E> last(S target, Action<S, E> action, Action<S, E> error);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 2017 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,9 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.model;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
|
||||
/**
|
||||
@@ -27,6 +30,7 @@ public class ChoiceData<S, E> {
|
||||
private final S source;
|
||||
private final S target;
|
||||
private final Guard<S, E> guard;
|
||||
private final Collection<Action<S, E>> actions;
|
||||
|
||||
/**
|
||||
* Instantiates a new choice data.
|
||||
@@ -36,9 +40,22 @@ public class ChoiceData<S, E> {
|
||||
* @param guard the guard
|
||||
*/
|
||||
public ChoiceData(S source, S target, Guard<S, E> guard) {
|
||||
this(source, target, guard, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new choice data.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param guard the guard
|
||||
* @param actions the actions
|
||||
*/
|
||||
public ChoiceData(S source, S target, Guard<S, E> guard, Collection<Action<S, E>> actions) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.guard = guard;
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,4 +84,13 @@ public class ChoiceData<S, E> {
|
||||
public Guard<S, E> getGuard() {
|
||||
return guard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the actions.
|
||||
*
|
||||
* @return the actions
|
||||
*/
|
||||
public Collection<Action<S, E>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 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,9 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config.model;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
|
||||
/**
|
||||
@@ -27,6 +30,7 @@ public class JunctionData<S, E> {
|
||||
private final S source;
|
||||
private final S target;
|
||||
private final Guard<S, E> guard;
|
||||
private final Collection<Action<S, E>> actions;
|
||||
|
||||
/**
|
||||
* Instantiates a new junction data.
|
||||
@@ -36,9 +40,22 @@ public class JunctionData<S, E> {
|
||||
* @param guard the guard
|
||||
*/
|
||||
public JunctionData(S source, S target, Guard<S, E> guard) {
|
||||
this(source, target, guard, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new junction data.
|
||||
*
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param guard the guard
|
||||
* @param actions the actions
|
||||
*/
|
||||
public JunctionData(S source, S target, Guard<S, E> guard, Collection<Action<S, E>> actions) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.guard = guard;
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,4 +84,13 @@ public class JunctionData<S, E> {
|
||||
public Guard<S, E> getGuard() {
|
||||
return guard;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the actions.
|
||||
*
|
||||
* @return the actions
|
||||
*/
|
||||
public Collection<Action<S, E>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 2017 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,11 +15,13 @@
|
||||
*/
|
||||
package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
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.guard.Guard;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -53,12 +55,17 @@ public class ChoicePseudoState<S, E> implements PseudoState<S, E> {
|
||||
@Override
|
||||
public State<S, E> entry(StateContext<S, E> context) {
|
||||
State<S, E> s = null;
|
||||
ChoiceStateData<S, E> csd = null;
|
||||
for (ChoiceStateData<S, E> c : choices) {
|
||||
s = c.getState();
|
||||
csd = c;
|
||||
if (c.guard != null && evaluateInternal(c.guard, context)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (csd != null) {
|
||||
s = csd.getState();
|
||||
executeActions(csd.getActions(), context);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -83,6 +90,19 @@ public class ChoicePseudoState<S, E> implements PseudoState<S, E> {
|
||||
}
|
||||
}
|
||||
|
||||
private void executeActions(Collection<Action<S, E>> actions, StateContext<S, E> context) {
|
||||
if (actions == null) {
|
||||
return;
|
||||
}
|
||||
for (Action<S, E> action : actions) {
|
||||
try {
|
||||
action.execute(context);
|
||||
} catch (Throwable t) {
|
||||
log.warn("Action execution resulted error", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data class wrapping choice {@link State} and {@link Guard}
|
||||
* together.
|
||||
@@ -93,17 +113,20 @@ public class ChoicePseudoState<S, E> implements PseudoState<S, E> {
|
||||
public static class ChoiceStateData<S, E> {
|
||||
private final StateHolder<S, E> state;
|
||||
private final Guard<S, E> guard;
|
||||
private final Collection<Action<S, E>> actions;
|
||||
|
||||
/**
|
||||
* Instantiates a new choice state data.
|
||||
*
|
||||
* @param state the state holder
|
||||
* @param guard the guard
|
||||
* @param actions the actions
|
||||
*/
|
||||
public ChoiceStateData(StateHolder<S, E> state, Guard<S, E> guard) {
|
||||
public ChoiceStateData(StateHolder<S, E> state, Guard<S, E> guard, Collection<Action<S, E>> actions) {
|
||||
Assert.notNull(state, "Holder must be set");
|
||||
this.state = state;
|
||||
this.guard = guard;
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,5 +155,14 @@ public class ChoicePseudoState<S, E> implements PseudoState<S, E> {
|
||||
public Guard<S, E> getGuard() {
|
||||
return guard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the actions.
|
||||
*
|
||||
* @return the actions
|
||||
*/
|
||||
public Collection<Action<S, E>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 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,11 +15,13 @@
|
||||
*/
|
||||
package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
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.guard.Guard;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -53,12 +55,17 @@ public class JunctionPseudoState<S, E> implements PseudoState<S, E> {
|
||||
@Override
|
||||
public State<S, E> entry(StateContext<S, E> context) {
|
||||
State<S, E> s = null;
|
||||
JunctionStateData<S, E> jsd = null;
|
||||
for (JunctionStateData<S, E> j : junctions) {
|
||||
s = j.getState();
|
||||
jsd = j;
|
||||
if (j.guard != null && evaluateInternal(j.guard, context)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jsd != null) {
|
||||
s = jsd.getState();
|
||||
executeActions(jsd.getActions(), context);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -83,6 +90,19 @@ public class JunctionPseudoState<S, E> implements PseudoState<S, E> {
|
||||
}
|
||||
}
|
||||
|
||||
private void executeActions(Collection<Action<S, E>> actions, StateContext<S, E> context) {
|
||||
if (actions == null) {
|
||||
return;
|
||||
}
|
||||
for (Action<S, E> action : actions) {
|
||||
try {
|
||||
action.execute(context);
|
||||
} catch (Throwable t) {
|
||||
log.warn("Action execution resulted error", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data class wrapping choice {@link State} and {@link Guard}
|
||||
* together.
|
||||
@@ -93,17 +113,20 @@ public class JunctionPseudoState<S, E> implements PseudoState<S, E> {
|
||||
public static class JunctionStateData<S, E> {
|
||||
private final StateHolder<S, E> state;
|
||||
private final Guard<S, E> guard;
|
||||
private final Collection<Action<S, E>> actions;
|
||||
|
||||
/**
|
||||
* Instantiates a new junction state data.
|
||||
*
|
||||
* @param state the state holder
|
||||
* @param guard the guard
|
||||
* @param actions the actions
|
||||
*/
|
||||
public JunctionStateData(StateHolder<S, E> state, Guard<S, E> guard) {
|
||||
public JunctionStateData(StateHolder<S, E> state, Guard<S, E> guard, Collection<Action<S, E>> actions) {
|
||||
Assert.notNull(state, "Holder must be set");
|
||||
this.state = state;
|
||||
this.guard = guard;
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,5 +155,14 @@ public class JunctionPseudoState<S, E> implements PseudoState<S, E> {
|
||||
public Guard<S, E> getGuard() {
|
||||
return guard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the actions.
|
||||
*
|
||||
* @return the actions
|
||||
*/
|
||||
public Collection<Action<S, E>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,6 +747,48 @@ public class DocsConfigurationSampleTests extends AbstractStateMachineTests {
|
||||
}
|
||||
// end::snippetS[]
|
||||
|
||||
// tag::snippetSSS[]
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public class Config23
|
||||
extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<States, Events> states)
|
||||
throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(States.SI)
|
||||
.choice(States.S1)
|
||||
.end(States.SF)
|
||||
.states(EnumSet.allOf(States.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
|
||||
throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(States.SI)
|
||||
.action(c -> {
|
||||
// action with SI-S1
|
||||
})
|
||||
.target(States.S1)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(States.S1)
|
||||
.first(States.S2, c -> {
|
||||
return true;
|
||||
})
|
||||
.last(States.S3, c -> {
|
||||
// action with S1-S3
|
||||
}, c -> {
|
||||
// error callback for action S1-S3
|
||||
});
|
||||
}
|
||||
}
|
||||
// end::snippetSSS[]
|
||||
|
||||
// tag::snippetSS[]
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -23,6 +23,8 @@ import static org.junit.Assert.assertThat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
@@ -33,6 +35,7 @@ import org.springframework.statemachine.AbstractStateMachineTests;
|
||||
import org.springframework.statemachine.ObjectStateMachine;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
@@ -156,6 +159,44 @@ public class ChoiceStateTests extends AbstractStateMachineTests {
|
||||
assertThat(listener.entered.size(), is(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testTransitionToChoiceActionCalled1() throws InterruptedException {
|
||||
context.register(Config5.class);
|
||||
context.refresh();
|
||||
ObjectStateMachine<TestStates,TestEvents> machine =
|
||||
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
|
||||
LatchAction sIToChoice = context.getBean("sIToChoice", LatchAction.class);
|
||||
LatchAction choiceToS30 = context.getBean("choiceToS30", LatchAction.class);
|
||||
LatchAction choiceToS33 = context.getBean("choiceToS33", LatchAction.class);
|
||||
assertThat(machine, notNullValue());
|
||||
machine.start();
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).setHeader("choice", "s30").build());
|
||||
assertThat(sIToChoice.latch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(choiceToS30.latch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(choiceToS33.latch.await(1, TimeUnit.SECONDS), is(false));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S30));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testTransitionToChoiceActionCalled2() throws InterruptedException {
|
||||
context.register(Config5.class);
|
||||
context.refresh();
|
||||
ObjectStateMachine<TestStates,TestEvents> machine =
|
||||
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
|
||||
LatchAction sIToChoice = context.getBean("sIToChoice", LatchAction.class);
|
||||
LatchAction choiceToS30 = context.getBean("choiceToS30", LatchAction.class);
|
||||
LatchAction choiceToS33 = context.getBean("choiceToS33", LatchAction.class);
|
||||
assertThat(machine, notNullValue());
|
||||
machine.start();
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
|
||||
assertThat(sIToChoice.latch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(choiceToS30.latch.await(1, TimeUnit.SECONDS), is(false));
|
||||
assertThat(choiceToS33.latch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S33));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class Config1 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
|
||||
@@ -324,6 +365,73 @@ public class ChoiceStateTests extends AbstractStateMachineTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class Config5 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(TestStates.SI)
|
||||
.states(EnumSet.allOf(TestStates.class))
|
||||
.choice(TestStates.S3)
|
||||
.end(TestStates.SF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(TestStates.SI)
|
||||
.target(TestStates.S3)
|
||||
.action(sIToChoice())
|
||||
.event(TestEvents.E1)
|
||||
.and()
|
||||
.withChoice()
|
||||
.source(TestStates.S3)
|
||||
.first(TestStates.S30, s30Guard(), choiceToS30())
|
||||
.then(TestStates.S31, s31Guard())
|
||||
.then(TestStates.S32, s32Guard())
|
||||
.last(TestStates.S33, choiceToS33(), choiceToS33Error());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<TestStates, TestEvents> s30Guard() {
|
||||
return new ChoiceGuard("s30");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<TestStates, TestEvents> s31Guard() {
|
||||
return new ChoiceGuard("s31");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<TestStates, TestEvents> s32Guard() {
|
||||
return new ChoiceGuard("s32");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<TestStates, TestEvents> sIToChoice() {
|
||||
return new LatchAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<TestStates, TestEvents> choiceToS30() {
|
||||
return new LatchAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<TestStates, TestEvents> choiceToS33() {
|
||||
return new LatchAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<TestStates, TestEvents> choiceToS33Error() {
|
||||
return new LatchAction();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestStateEntryExitListener extends StateMachineListenerAdapter<TestStates, TestEvents> {
|
||||
|
||||
List<State<TestStates, TestEvents>> entered = new ArrayList<>();
|
||||
@@ -359,4 +467,12 @@ public class ChoiceStateTests extends AbstractStateMachineTests {
|
||||
}
|
||||
}
|
||||
|
||||
private static class LatchAction implements Action<TestStates, TestEvents> {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<TestStates, TestEvents> context) {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
package org.springframework.statemachine.state;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
@@ -30,6 +33,7 @@ import org.springframework.statemachine.AbstractStateMachineTests;
|
||||
import org.springframework.statemachine.ObjectStateMachine;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
@@ -128,6 +132,44 @@ public class JunctionStateTests extends AbstractStateMachineTests {
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S21));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testTransitionToJunctionActionCalled1() throws InterruptedException {
|
||||
context.register(Config4.class);
|
||||
context.refresh();
|
||||
ObjectStateMachine<TestStates,TestEvents> machine =
|
||||
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
|
||||
LatchAction sIToJunction = context.getBean("sIToJunction", LatchAction.class);
|
||||
LatchAction junctionToS30 = context.getBean("junctionToS30", LatchAction.class);
|
||||
LatchAction junctionToS33 = context.getBean("junctionToS33", LatchAction.class);
|
||||
assertThat(machine, notNullValue());
|
||||
machine.start();
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).setHeader("junction", "s30").build());
|
||||
assertThat(sIToJunction.latch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(junctionToS30.latch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(junctionToS33.latch.await(1, TimeUnit.SECONDS), is(false));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S30));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testTransitionToJunctionActionCalled2() throws InterruptedException {
|
||||
context.register(Config4.class);
|
||||
context.refresh();
|
||||
ObjectStateMachine<TestStates,TestEvents> machine =
|
||||
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
|
||||
LatchAction sIToJunction = context.getBean("sIToJunction", LatchAction.class);
|
||||
LatchAction junctionToS30 = context.getBean("junctionToS30", LatchAction.class);
|
||||
LatchAction junctionToS33 = context.getBean("junctionToS33", LatchAction.class);
|
||||
assertThat(machine, notNullValue());
|
||||
machine.start();
|
||||
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
|
||||
assertThat(sIToJunction.latch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(junctionToS30.latch.await(1, TimeUnit.SECONDS), is(false));
|
||||
assertThat(junctionToS33.latch.await(1, TimeUnit.SECONDS), is(true));
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S33));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class Config1 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
|
||||
@@ -264,6 +306,73 @@ public class JunctionStateTests extends AbstractStateMachineTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class Config4 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(TestStates.SI)
|
||||
.states(EnumSet.allOf(TestStates.class))
|
||||
.junction(TestStates.S3)
|
||||
.end(TestStates.SF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(TestStates.SI)
|
||||
.target(TestStates.S3)
|
||||
.action(sIToJunction())
|
||||
.event(TestEvents.E1)
|
||||
.and()
|
||||
.withJunction()
|
||||
.source(TestStates.S3)
|
||||
.first(TestStates.S30, s30Guard(), junctionToS30())
|
||||
.then(TestStates.S31, s31Guard())
|
||||
.then(TestStates.S32, s32Guard())
|
||||
.last(TestStates.S33, junctionToS33(), junctionToS33Error());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<TestStates, TestEvents> s30Guard() {
|
||||
return new JunctionGuard("s30");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<TestStates, TestEvents> s31Guard() {
|
||||
return new JunctionGuard("s31");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Guard<TestStates, TestEvents> s32Guard() {
|
||||
return new JunctionGuard("s32");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<TestStates, TestEvents> sIToJunction() {
|
||||
return new LatchAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<TestStates, TestEvents> junctionToS30() {
|
||||
return new LatchAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<TestStates, TestEvents> junctionToS33() {
|
||||
return new LatchAction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<TestStates, TestEvents> junctionToS33Error() {
|
||||
return new LatchAction();
|
||||
}
|
||||
}
|
||||
|
||||
private static class JunctionGuard implements Guard<TestStates, TestEvents> {
|
||||
|
||||
private final String match;
|
||||
@@ -278,4 +387,12 @@ public class JunctionStateTests extends AbstractStateMachineTests {
|
||||
}
|
||||
}
|
||||
|
||||
private static class LatchAction implements Action<TestStates, TestEvents> {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<TestStates, TestEvents> context) {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user