package org.squirrelframework.foundation.fsm.impl; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import org.apache.commons.lang3.StringUtils; import org.squirrelframework.foundation.component.SquirrelComponent; import org.squirrelframework.foundation.fsm.*; import org.squirrelframework.foundation.fsm.builder.*; import java.util.List; import java.util.Map; /** * Created by kailianghe on 7/12/14. */ class MultiTransitionBuilderImpl<T extends StateMachine<T, S, E, C>, S, E, C> implements MultiTransitionBuilder<T, S, E, C>, MultiFrom<T, S, E, C>, From<T, S, E, C>, MultiTo<T, S, E, C>, To<T, S, E, C>, On<T, S, E, C>, Between<T, S, E, C>, And<T, S, E, C>, SquirrelComponent { private final List<MutableTransition<T, S, E, C>> transitions = Lists.newArrayList(); private final List<MutableState<T, S, E, C>> sourceStates = Lists.newArrayList(); private final List<MutableState<T, S, E, C>> targetStates = Lists.newArrayList(); private final Map<S, MutableState<T, S, E, C>> states; private final int priority; private final ExecutionContext executionContext; private final TransitionType transitionType; MultiTransitionBuilderImpl(Map<S, MutableState<T, S, E, C>> states, TransitionType transitionType, int priority, ExecutionContext executionContext) { this.states = states; this.transitionType = transitionType; this.priority = priority; this.executionContext = executionContext; } @Override public MultiTo<T, S, E, C> toAmong(S... stateIds) { for(S stateId : stateIds) { targetStates.add(FSM.getState(states, stateId)); } return this; } @Override public To<T, S, E, C> to(S stateId) { targetStates.add(FSM.getState(states, stateId)); return this; } @Override public To<T, S, E, C> toFinal(S stateId) { MutableState<T, S, E, C> targetState = FSM.getState(states, stateId); if(!targetState.isFinalState()) { targetState.setFinal(true); } targetStates.add(targetState); return this; } @Override public MultiFrom<T, S, E, C> from(S stateId) { sourceStates.add(FSM.getState(states, stateId)); return this; } @Override public From<T, S, E, C> fromAmong(S... stateIds) { for(S stateId : stateIds) { sourceStates.add(FSM.getState(states, stateId)); } return this; } @Override public Between<T, S, E, C> between(S fromStateId) { sourceStates.add(FSM.getState(states, fromStateId)); return this; } @Override public And<T, S, E, C> and(S stateId) { targetStates.add(FSM.getState(states, stateId)); return this; } @Override public On<T, S, E, C> onMutual(E fromEvent, E toEvent) { MutableTransition<T, S, E, C> forwardTransition = sourceStates.get(0).addTransitionOn(fromEvent); forwardTransition.setTargetState(targetStates.get(0)); forwardTransition.setType(transitionType); forwardTransition.setPriority(priority); transitions.add(forwardTransition); MutableTransition<T, S, E, C> backwardTransition = targetStates.get(0).addTransitionOn(toEvent); backwardTransition.setTargetState(sourceStates.get(0)); backwardTransition.setType(transitionType); backwardTransition.setPriority(priority); transitions.add(backwardTransition); return this; } @Override public On<T, S, E, C> on(E event) { for(MutableState<T, S, E, C> sourceState : sourceStates) { for(MutableState<T, S, E, C> targetState : targetStates) { MutableTransition<T, S, E, C> transition = sourceState.addTransitionOn(event); transition.setTargetState(targetState); transition.setType(transitionType); transition.setPriority(priority); transitions.add(transition); } } return this; } @Override public On<T, S, E, C> onEach(E... events) { Preconditions.checkNotNull(events); int eventLength = events.length; for(int i=0, srcStateLength=sourceStates.size(); i<srcStateLength; ++i) { for(int j=0, tarStateLength=targetStates.size(); j<tarStateLength; ++j) { int statePos = j<i ? i : j; int eventPos = statePos<eventLength ? statePos : eventLength-1; MutableTransition<T, S, E, C> transition = sourceStates.get(i).addTransitionOn(events[eventPos]); transition.setTargetState(targetStates.get(j)); transition.setType(transitionType); transition.setPriority(priority); transitions.add(transition); } } return this; } @Override public When<T, S, E, C> when(Condition<C> condition) { for(MutableTransition<T, S, E, C> transition : transitions) { transition.setCondition(condition); } return this; } @Override public When<T, S, E, C> whenMvel(String expression) { for(MutableTransition<T, S, E, C> transition : transitions) { Condition<C> cond = FSM.newMvelCondition(expression, executionContext.getScriptManager()); transition.setCondition(cond); } return this; } @Override public void perform(Action<T, S, E, C> action) { for(MutableTransition<T, S, E, C> transition : transitions) { transition.addAction(action); } } @Override public void perform(List<? extends Action<T, S, E, C>> actions) { int actionSize = actions.size(); for(int i=0, transitionLength=transitions.size(); i<transitionLength; ++i) { int actionPos = i<actionSize ? i : actionSize-1; transitions.get(i).addAction(actions.get(actionPos)); } } @Override public void evalMvel(String expression) { for(MutableTransition<T, S, E, C> transition : transitions) { Action<T, S, E, C> action = FSM.newMvelAction(expression, executionContext); transition.addAction(action); } } @Override public void callMethod(String methodName) { String[] methods = StringUtils.split(methodName, '|'); int methodsLength = methods.length; for(int i=0, transitionLength=transitions.size(); i<transitionLength; ++i) { int methodPos = i<methodsLength ? i : methodsLength-1; String theMethodName = methods[methodPos].trim(); if("_".equals(theMethodName)) continue; Action<T, S, E, C> action = FSM.newMethodCallActionProxy(theMethodName, executionContext); transitions.get(i).addAction(action); } } }