Skip to content

Commit

Permalink
Merge pull request #486 from wl2027/master
Browse files Browse the repository at this point in the history
状态机增加轻量的并行节点配置
  • Loading branch information
significantfrank committed Apr 21, 2024
2 parents 22f6367 + e0b79c0 commit 1a8c433
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public interface State<S,E,C> extends Visitable{
*/
Transition<S,E,C> addTransition(E event, State<S, E, C> target, TransitionType transitionType);

List<Transition<S,E,C>> addTransitions(E event, List<State<S, E, C>> targets, TransitionType transitionType);

List<Transition<S,E,C>> getEventTransitions(E event);

Collection<Transition<S,E,C>> getAllTransitions();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.alibaba.cola.statemachine;

import java.util.List;

/**
* StateMachine
*
Expand Down Expand Up @@ -30,6 +32,8 @@ public interface StateMachine<S, E, C> extends Visitable{
*/
S fireEvent(S sourceState, E event, C ctx);

List<S> fireParallelEvent(S sourceState, E event, C ctx);

/**
* MachineId is the identifier for a State Machine
* @return
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.alibaba.cola.statemachine.builder;

import com.alibaba.cola.statemachine.State;
import com.alibaba.cola.statemachine.impl.StateHelper;
import com.alibaba.cola.statemachine.impl.TransitionType;

import java.util.List;
import java.util.Map;

abstract class AbstractParallelTransitionBuilder<S,E,C> implements ParallelFrom<S,E,C>,On<S,E,C>,To<S,E,C>{

final Map<S, State<S, E, C>> stateMap;

protected List<State<S, E, C>> targets;

final TransitionType transitionType;

public AbstractParallelTransitionBuilder(Map<S, State<S, E, C>> stateMap, TransitionType transitionType) {
this.stateMap = stateMap;
this.transitionType = transitionType;
}
@Override
public To<S, E, C> toAmong(S ... stateIds) {
targets = StateHelper.getStates(stateMap, stateIds);
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.alibaba.cola.statemachine.builder;


public interface ExternalParallelTransitionBuilder<S, E, C> {
/**
* Build transition source state.
* @param stateId id of state
* @return from clause builder
*/
ParallelFrom<S, E, C> from(S stateId);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.alibaba.cola.statemachine.builder;


public interface ParallelFrom<S, E, C> {
/**
* Build transition target state and return to clause builder
* @param stateIds id of state
* @return To clause builder
*/
To<S, E, C> toAmong(S ... stateIds);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.alibaba.cola.statemachine.builder;

import com.alibaba.cola.statemachine.Action;
import com.alibaba.cola.statemachine.Condition;
import com.alibaba.cola.statemachine.State;
import com.alibaba.cola.statemachine.Transition;
import com.alibaba.cola.statemachine.impl.StateHelper;
import com.alibaba.cola.statemachine.impl.TransitionType;

import java.util.List;
import java.util.Map;

class ParallelTransitionBuilderImpl<S,E,C> extends AbstractParallelTransitionBuilder<S,E,C> implements ExternalParallelTransitionBuilder<S,E,C> {


private State<S, E, C> source;
private List<Transition<S, E, C>> transitions;

public ParallelTransitionBuilderImpl(Map<S, State<S, E, C>> stateMap, TransitionType transitionType) {
super(stateMap, transitionType);
}

@Override
public ParallelFrom<S, E, C> from(S stateId) {
source = StateHelper.getState(stateMap, stateId);
return this;
}

@Override
public When<S, E, C> when(Condition<C> condition) {
for (Transition<S, E, C> transition : transitions) {
transition.setCondition(condition);
}
return this;
}

@Override
public On<S, E, C> on(E event) {
transitions = source.addTransitions(event, targets, transitionType);
return this;
}

@Override
public void perform(Action<S, E, C> action) {
for (Transition<S, E, C> transition : transitions) {
transition.setAction(action);
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public interface StateMachineBuilder<S, E, C> {
* @return External transition builder
*/
ExternalTransitionsBuilder<S, E, C> externalTransitions();
/**
* Builder for parallel transitions
*
* @return External transition builder
*/
ExternalParallelTransitionBuilder<S, E, C> externalParallelTransition();

/**
* Start to build internal transition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public ExternalTransitionsBuilder<S, E, C> externalTransitions() {
return new TransitionsBuilderImpl<>(stateMap, TransitionType.EXTERNAL);
}

@Override
public ExternalParallelTransitionBuilder<S, E, C> externalParallelTransition() {
return new ParallelTransitionBuilderImpl<>(stateMap, TransitionType.EXTERNAL);
}

@Override
public InternalTransitionBuilder<S, E, C> internalTransition() {
return new TransitionBuilderImpl<>(stateMap, TransitionType.INTERNAL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.alibaba.cola.statemachine.State;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
Expand All @@ -19,4 +21,12 @@ public static <S, E, C> State<S, E, C> getState(Map<S, State<S, E, C>> stateMap,
}
return state;
}
public static <C, E, S> List<State<S,E,C>> getStates(Map<S, State<S,E,C>> stateMap, S ... stateIds) {
List<State<S, E, C>> result = new ArrayList<>();
for (S stateId : stateIds) {
State<S, E, C> state = getState(stateMap, stateId);
result.add(state);
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.alibaba.cola.statemachine.Transition;
import com.alibaba.cola.statemachine.Visitor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

Expand Down Expand Up @@ -35,6 +36,17 @@ public Transition<S, E, C> addTransition(E event, State<S,E,C> target, Transitio
return newTransition;
}

@Override
public List<Transition<S, E, C>> addTransitions(E event, List<State<S, E, C>> targets, TransitionType transitionType) {
List<Transition<S, E, C>> result = new ArrayList<>();
for (State<S, E, C> target : targets) {
Transition<S, E, C> secTransition = addTransition(event, target, transitionType);
result.add(secTransition);
}

return result;
}

@Override
public List<Transition<S, E, C>> getEventTransitions(E event) {
return eventTransitions.get(event);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.alibaba.cola.statemachine.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -57,6 +58,23 @@ public S fireEvent(S sourceStateId, E event, C ctx) {

return transition.transit(ctx, false).getId();
}
@Override
public List<S> fireParallelEvent(S sourceState, E event, C context) {
isReady();
List<Transition<S, E, C>> transitions = routeTransitions(sourceState, event, context);
List<S> result = new ArrayList<>();
if (transitions == null||transitions.isEmpty()) {
Debugger.debug("There is no Transition for " + event);
failCallback.onFail(sourceState, event, context);
result.add(sourceState);
return result;
}
for (Transition<S, E, C> transition : transitions) {
S id = transition.transit(context, false).getId();
result.add(id);
}
return result;
}

private Transition<S, E, C> routeTransition(S sourceStateId, E event, C ctx) {
State sourceState = getState(sourceStateId);
Expand All @@ -79,6 +97,25 @@ private Transition<S, E, C> routeTransition(S sourceStateId, E event, C ctx) {

return transit;
}
private List<Transition<S,E,C>> routeTransitions(S sourceStateId, E event, C context) {
State sourceState = getState(sourceStateId);
List<Transition<S, E, C>> result = new ArrayList<>();
List<Transition<S, E, C>> transitions = sourceState.getEventTransitions(event);
if (transitions == null || transitions.size() == 0) {
return null;
}

for (Transition<S, E, C> transition : transitions) {
Transition<S, E, C> transit = null;
if (transition.getCondition() == null) {
transit = transition;
} else if (transition.getCondition().isSatisfied(context)) {
transit = transition;
}
result.add(transit);
}
return result;
}

private State getState(S currentStateId) {
State state = StateHelper.getState(stateMap, currentStateId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import org.junit.Assert;
import org.junit.Test;

import java.util.List;

/**
* StateMachineTest
*
Expand Down Expand Up @@ -210,6 +212,32 @@ public void testMultiThread() {
}

}
@Test
public void testParallel(){
StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();
builder.externalParallelTransition()
.from(States.STATE1)
.toAmong(States.STATE2,States.STATE3)
.on(StateMachineTest.Events.EVENT1)
.when(checkCondition())
.perform(doAction());
builder.externalTransitions()
.fromAmong(StateMachineTest.States.STATE2,StateMachineTest.States.STATE3)
.to(StateMachineTest.States.STATE4)
.on(StateMachineTest.Events.EVENT2)
.when(checkCondition())
.perform(doAction());
StateMachine<States, Events, Context> stateMachine = builder.build("ParallelMachine");
System.out.println(stateMachine.generatePlantUML());
List<States> states = stateMachine.fireParallelEvent(StateMachineTest.States.STATE1, StateMachineTest.Events.EVENT1, new Context());
for (StateMachineTest.States state : states) {
System.out.println(state);
}
States target2 = stateMachine.fireEvent(StateMachineTest.States.STATE2, StateMachineTest.Events.EVENT2, new Context());
Assert.assertEquals(States.STATE4,target2);
States target3 = stateMachine.fireEvent(StateMachineTest.States.STATE3, StateMachineTest.Events.EVENT2, new Context());
Assert.assertEquals(States.STATE4,target3);
}

private Condition<Context> checkCondition() {
return new Condition<Context>() {
Expand Down

0 comments on commit 1a8c433

Please sign in to comment.