Add base work for recipes
- Better state sync handling #35 - Adding first recipe for synching and persisting a state # 73
This commit is contained in:
@@ -17,6 +17,7 @@ package org.springframework.statemachine.access;
|
||||
|
||||
import org.springframework.statemachine.ExtendedState;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.support.StateChangeInterceptor;
|
||||
|
||||
/**
|
||||
* Functional interface exposing {@link StateMachine} internals.
|
||||
@@ -49,4 +50,11 @@ public interface StateMachineAccess<S, E> {
|
||||
*/
|
||||
void setExtendedState(ExtendedState extendedState);
|
||||
|
||||
/**
|
||||
* Adds the state change interceptor.
|
||||
*
|
||||
* @param interceptor the interceptor
|
||||
*/
|
||||
void addStateChangeInterceptor(StateChangeInterceptor<S, E> interceptor);
|
||||
|
||||
}
|
||||
|
||||
@@ -259,6 +259,8 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
protected void doStart() {
|
||||
// if state is set assume nothing to do
|
||||
if (currentState != null) {
|
||||
stateMachineExecutor.setInitialEnabled(false);
|
||||
stateMachineExecutor.start();
|
||||
return;
|
||||
}
|
||||
registerPseudoStateListener();
|
||||
@@ -396,6 +398,11 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStateChangeInterceptor(StateChangeInterceptor<S, E> interceptor) {
|
||||
getStateChangeInterceptors().add(interceptor);
|
||||
}
|
||||
|
||||
protected boolean acceptEvent(Message<E> message) {
|
||||
|
||||
boolean accepted = currentState.sendEvent(message);
|
||||
@@ -430,7 +437,20 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean callStateChangeInterceptors(State<S,E> state, Message<E> message, Transition<S,E> transition, StateMachine<S, E> stateMachine) {
|
||||
try {
|
||||
getStateChangeInterceptors().preStateChange(state, message, transition, stateMachine);
|
||||
} catch (Exception e) {
|
||||
log.info("Interceptors threw and exception, skipping state change", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void switchToState(State<S,E> state, Message<E> message, Transition<S,E> transition, StateMachine<S, E> stateMachine) {
|
||||
if (!callStateChangeInterceptors(state, message, transition, stateMachine)) {
|
||||
return;
|
||||
}
|
||||
// TODO: need to make below more clear when
|
||||
// we figure out rest of a pseudostates
|
||||
PseudoStateKind kind = state.getPseudoState() != null ? state.getPseudoState().getKind() : null;
|
||||
|
||||
@@ -147,6 +147,13 @@ public class DefaultStateMachineExecutor<S, E> extends LifecycleObjectSupport im
|
||||
initialHandled.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInitialEnabled(boolean enabled) {
|
||||
// TODO: should prob handle case where this is enabled
|
||||
// when executor is running
|
||||
initialHandled.set(!enabled);
|
||||
}
|
||||
|
||||
private void handleTriggerTrans(List<Transition<S, E>> trans, Message<E> queuedMessage) {
|
||||
for (Transition<S, E> t : trans) {
|
||||
if (t == null) {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2015 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.support;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
public interface StateChangeInterceptor<S, E> {
|
||||
|
||||
void preStateChange(State<S,E> state, Message<E> message, Transition<S,E> transition, StateMachine<S, E> stateMachine);
|
||||
|
||||
}
|
||||
@@ -58,6 +58,13 @@ public interface StateMachineExecutor<S, E> {
|
||||
*/
|
||||
void execute();
|
||||
|
||||
/**
|
||||
* Sets the if initial stage is enabled.
|
||||
*
|
||||
* @param enabled the new flag
|
||||
*/
|
||||
void setInitialEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Start executor.
|
||||
*
|
||||
|
||||
@@ -15,8 +15,15 @@
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.event.StateMachineEventPublisher;
|
||||
@@ -46,6 +53,9 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
/** Flag for application context events */
|
||||
private boolean contextEventsEnabled = true;
|
||||
|
||||
private final StateChangeInterceptorList interceptors =
|
||||
new StateChangeInterceptorList();
|
||||
|
||||
/**
|
||||
* Gets the state machine event publisher.
|
||||
*
|
||||
@@ -186,6 +196,15 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
// re-scheduling is needed.
|
||||
}
|
||||
|
||||
protected StateChangeInterceptorList getStateChangeInterceptors() {
|
||||
return interceptors;
|
||||
}
|
||||
|
||||
protected void setStateChangeInterceptors(List<StateChangeInterceptor<S,E>> interceptors) {
|
||||
Collections.sort(interceptors, new OrderComparator());
|
||||
this.interceptors.set(interceptors);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is used to relay listener events from a submachines which works
|
||||
* as its own listener context. User only connects to main root machine and
|
||||
@@ -241,4 +260,53 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
|
||||
}
|
||||
|
||||
protected class StateChangeInterceptorList {
|
||||
|
||||
private final List<StateChangeInterceptor<S, E>> interceptors = new CopyOnWriteArrayList<StateChangeInterceptor<S, E>>();
|
||||
|
||||
/**
|
||||
* Sets the interceptors, clears any existing interceptors.
|
||||
*
|
||||
* @param interceptors the list of interceptors
|
||||
* @return <tt>true</tt> if interceptor list changed as a result of the
|
||||
* call
|
||||
*/
|
||||
public boolean set(List<StateChangeInterceptor<S, E>> interceptors) {
|
||||
synchronized (interceptors) {
|
||||
interceptors.clear();
|
||||
return interceptors.addAll(interceptors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds interceptor to the list.
|
||||
*
|
||||
* @param interceptor the interceptor
|
||||
* @return <tt>true</tt> (as specified by {@link Collection#add})
|
||||
*/
|
||||
public boolean add(StateChangeInterceptor<S, E> interceptor) {
|
||||
return interceptors.add(interceptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes interceptor from the list.
|
||||
*
|
||||
* @param interceptor the interceptor
|
||||
* @return <tt>true</tt> (as specified by {@link Collection#remove})
|
||||
*/
|
||||
public boolean remove(StateChangeInterceptor<S, E> interceptor) {
|
||||
return interceptors.remove(interceptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the pre state change calls.
|
||||
*/
|
||||
void preStateChange(State<S, E> state, Message<E> message, Transition<S, E> transition,
|
||||
StateMachine<S, E> stateMachine) {
|
||||
for (StateChangeInterceptor<S, E> interceptor : interceptors) {
|
||||
interceptor.preStateChange(state, message, transition, stateMachine);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.statemachine.ExtendedState;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.listener.StateMachineListener;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.support.StateChangeInterceptor;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
public class StateMachineAccessTests {
|
||||
@@ -80,6 +81,10 @@ public class StateMachineAccessTests {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStateChangeInterceptor(StateChangeInterceptor<String, String> interceptor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRelay(StateMachine<String, String> stateMachine) {
|
||||
this.relay = stateMachine;
|
||||
|
||||
Reference in New Issue
Block a user