
org.squirrelframework.foundation.fsm.impl.LinkedStateImpl Maven / Gradle / Ivy
package org.squirrelframework.foundation.fsm.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.squirrelframework.foundation.component.SquirrelInstanceProvider;
import org.squirrelframework.foundation.fsm.Action;
import org.squirrelframework.foundation.fsm.AnonymousAction;
import org.squirrelframework.foundation.fsm.ImmutableLinkedState;
import org.squirrelframework.foundation.fsm.MutableLinkedState;
import org.squirrelframework.foundation.fsm.StateContext;
import org.squirrelframework.foundation.fsm.StateMachine;
import org.squirrelframework.foundation.fsm.StateMachineContext;
import org.squirrelframework.foundation.fsm.StateMachine.TransitionDeclinedEvent;
import org.squirrelframework.foundation.fsm.StateMachineStatus;
import com.google.common.collect.Maps;
class LinkedStateImpl, S, E, C> extends StateImpl
implements ImmutableLinkedState, MutableLinkedState {
class DeclineEventHandler implements StateMachine.TransitionDeclinedListener {
private StateContext orgStateContext;
DeclineEventHandler(StateContext orgStateContext) {
this.orgStateContext = orgStateContext;
}
@Override
public void transitionDeclined(TransitionDeclinedEvent event) {
LinkedStateImpl.super.internalFire(orgStateContext);
}
}
private SquirrelInstanceProvider extends StateMachine, S, E, C>> provider;
private Map, S, E, C>>
linkedStateMachineInstances = Maps.newConcurrentMap();
private Action lastEntryAction = new AnonymousAction() {
@Override
public void execute(S from, S to, E event, C context, T stateMachine) {
StateMachine extends StateMachine, S, E, C>, S, E, C> linkedStateMachine =
getLinkedStateMachine(stateMachine);
linkedStateMachine.start(context);
}
@Override
public String name() {
return "__LINK_STATE_ENTRY_ACTION";
}
};
private Action firstExitAction = new AnonymousAction() {
@Override
public void execute(S from, S to, E event, C context, T stateMachine) {
StateMachine extends StateMachine, S, E, C>, S, E, C> linkedStateMachine =
linkedStateMachineInstances.remove(getKey(stateMachine));
if(linkedStateMachine!=null) {
linkedStateMachine.terminate(context);
}
}
@Override
public String name() {
return "__LINK_STATE_EXIT_ACTION";
}
};
LinkedStateImpl(S stateId) {
super(stateId);
}
@Override
public void setLinkedStateMachineProvider(
SquirrelInstanceProvider extends StateMachine, S, E, C>> provider) {
this.provider = provider;
}
@SuppressWarnings({ "unchecked", "rawtypes" }) // TODO-hhe: check type safety
@Override
public void internalFire(StateContext stateContext) {
StateMachine extends StateMachine, S, E, C>, S, E, C> stateMachine =
linkedStateMachineInstances.get(getKey(stateContext.getStateMachine().getThis()));
if(stateMachine.getStatus()==StateMachineStatus.TERMINATED) {
// if linked state machine entered its final state, then outside state will process event,
super.internalFire(stateContext);
} else {
// otherwise the linked state machine will try to process event first and only handle event
// to outside state when event was declined by linked state machine.
DeclineEventHandler declinedEventHandler = new DeclineEventHandler(stateContext);
try {
// add declined event listener
stateMachine.addTransitionDeclinedListener(declinedEventHandler);
// set child(linked) state machine context
StateMachineContext.set(stateMachine.getThis(), StateMachineContext.isTestEvent());
// delegate the event to linked state machine process
stateMachine.fire(stateContext.getEvent(), stateContext.getContext());
} finally {
StateMachineContext.set(null);
// remove declined event listener
stateMachine.removeTransitionDecleindListener(declinedEventHandler);
}
}
}
@Override
public StateMachine extends StateMachine, S, E, C>, S, E, C> getLinkedStateMachine(T stateMachine) {
String key = getKey(stateMachine);
StateMachine extends StateMachine, S, E, C>, S, E, C> linkedStateMachine =
linkedStateMachineInstances.get(key);
if(linkedStateMachine==null) {
linkedStateMachine = provider.get();
linkedStateMachineInstances.put(key, linkedStateMachine);
}
return linkedStateMachine;
}
@Override
public List> getEntryActions() {
List> actions = new ArrayList>();
actions.addAll(entryActions.getAll());
actions.add(lastEntryAction);
return Collections.unmodifiableList(actions);
}
@Override
public List> getExitActions() {
List> actions = new ArrayList>();
actions.add(firstExitAction);
actions.addAll(exitActions.getAll());
return Collections.unmodifiableList(actions);
}
@Override
public void verify() {
if(provider==null) {
throw new IllegalStateException("Linked state machine provider cannot be null.");
}
if(isParallelState() || hasChildStates()) {
throw new IllegalStateException("Linked state cannot be parallel state or has any child states.");
}
super.verify();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy