From e0b79c0ec17ef2fd5493eafa29c5f185f36ef27d Mon Sep 17 00:00:00 2001 From: huangweilong Date: Thu, 18 Apr 2024 18:57:30 +0800 Subject: [PATCH] =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9C=BA=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=BD=BB=E9=87=8F=E7=9A=84=E5=B9=B6=E8=A1=8C=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.生成器方法:com.alibaba.cola.statemachine.builder.StateMachineBuilder.externalParallelTransition 2.测试方法:com.alibaba.cola.test.StateMachineTest.testParallel --- .../com/alibaba/cola/statemachine/State.java | 2 + .../cola/statemachine/StateMachine.java | 4 ++ .../AbstractParallelTransitionBuilder.java | 27 ++++++++++ .../ExternalParallelTransitionBuilder.java | 12 +++++ .../statemachine/builder/ParallelFrom.java | 12 +++++ .../ParallelTransitionBuilderImpl.java | 51 +++++++++++++++++++ .../builder/StateMachineBuilder.java | 6 +++ .../builder/StateMachineBuilderImpl.java | 5 ++ .../cola/statemachine/impl/StateHelper.java | 10 ++++ .../cola/statemachine/impl/StateImpl.java | 12 +++++ .../statemachine/impl/StateMachineImpl.java | 37 ++++++++++++++ .../alibaba/cola/test/StateMachineTest.java | 28 ++++++++++ 12 files changed, 206 insertions(+) create mode 100644 cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/AbstractParallelTransitionBuilder.java create mode 100644 cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ExternalParallelTransitionBuilder.java create mode 100644 cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ParallelFrom.java create mode 100644 cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ParallelTransitionBuilderImpl.java diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/State.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/State.java index 0296452f5..7657bfa41 100644 --- a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/State.java +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/State.java @@ -32,6 +32,8 @@ public interface State extends Visitable{ */ Transition addTransition(E event, State target, TransitionType transitionType); + List> addTransitions(E event, List> targets, TransitionType transitionType); + List> getEventTransitions(E event); Collection> getAllTransitions(); diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/StateMachine.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/StateMachine.java index 0e743a0d0..7febf1cc5 100644 --- a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/StateMachine.java +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/StateMachine.java @@ -1,5 +1,7 @@ package com.alibaba.cola.statemachine; +import java.util.List; + /** * StateMachine * @@ -30,6 +32,8 @@ public interface StateMachine extends Visitable{ */ S fireEvent(S sourceState, E event, C ctx); + List fireParallelEvent(S sourceState, E event, C ctx); + /** * MachineId is the identifier for a State Machine * @return diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/AbstractParallelTransitionBuilder.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/AbstractParallelTransitionBuilder.java new file mode 100644 index 000000000..46f6154db --- /dev/null +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/AbstractParallelTransitionBuilder.java @@ -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 implements ParallelFrom,On,To{ + + final Map> stateMap; + + protected List> targets; + + final TransitionType transitionType; + + public AbstractParallelTransitionBuilder(Map> stateMap, TransitionType transitionType) { + this.stateMap = stateMap; + this.transitionType = transitionType; + } + @Override + public To toAmong(S ... stateIds) { + targets = StateHelper.getStates(stateMap, stateIds); + return this; + } +} diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ExternalParallelTransitionBuilder.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ExternalParallelTransitionBuilder.java new file mode 100644 index 000000000..1f096addc --- /dev/null +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ExternalParallelTransitionBuilder.java @@ -0,0 +1,12 @@ +package com.alibaba.cola.statemachine.builder; + + +public interface ExternalParallelTransitionBuilder { + /** + * Build transition source state. + * @param stateId id of state + * @return from clause builder + */ + ParallelFrom from(S stateId); + +} diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ParallelFrom.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ParallelFrom.java new file mode 100644 index 000000000..8a2efd6d3 --- /dev/null +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ParallelFrom.java @@ -0,0 +1,12 @@ +package com.alibaba.cola.statemachine.builder; + + +public interface ParallelFrom { + /** + * Build transition target state and return to clause builder + * @param stateIds id of state + * @return To clause builder + */ + To toAmong(S ... stateIds); + +} diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ParallelTransitionBuilderImpl.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ParallelTransitionBuilderImpl.java new file mode 100644 index 000000000..69f0971fc --- /dev/null +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/ParallelTransitionBuilderImpl.java @@ -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 extends AbstractParallelTransitionBuilder implements ExternalParallelTransitionBuilder { + + + private State source; + private List> transitions; + + public ParallelTransitionBuilderImpl(Map> stateMap, TransitionType transitionType) { + super(stateMap, transitionType); + } + + @Override + public ParallelFrom from(S stateId) { + source = StateHelper.getState(stateMap, stateId); + return this; + } + + @Override + public When when(Condition condition) { + for (Transition transition : transitions) { + transition.setCondition(condition); + } + return this; + } + + @Override + public On on(E event) { + transitions = source.addTransitions(event, targets, transitionType); + return this; + } + + @Override + public void perform(Action action) { + for (Transition transition : transitions) { + transition.setAction(action); + } + } + + +} diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/StateMachineBuilder.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/StateMachineBuilder.java index 1b09ef410..6983687fc 100644 --- a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/StateMachineBuilder.java +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/StateMachineBuilder.java @@ -22,6 +22,12 @@ public interface StateMachineBuilder { * @return External transition builder */ ExternalTransitionsBuilder externalTransitions(); + /** + * Builder for parallel transitions + * + * @return External transition builder + */ + ExternalParallelTransitionBuilder externalParallelTransition(); /** * Start to build internal transition diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/StateMachineBuilderImpl.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/StateMachineBuilderImpl.java index f08365e26..3543c7b84 100644 --- a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/StateMachineBuilderImpl.java +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/builder/StateMachineBuilderImpl.java @@ -34,6 +34,11 @@ public ExternalTransitionsBuilder externalTransitions() { return new TransitionsBuilderImpl<>(stateMap, TransitionType.EXTERNAL); } + @Override + public ExternalParallelTransitionBuilder externalParallelTransition() { + return new ParallelTransitionBuilderImpl<>(stateMap, TransitionType.EXTERNAL); + } + @Override public InternalTransitionBuilder internalTransition() { return new TransitionBuilderImpl<>(stateMap, TransitionType.INTERNAL); diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateHelper.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateHelper.java index 46b348df4..a61ac28d4 100644 --- a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateHelper.java +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateHelper.java @@ -2,6 +2,8 @@ import com.alibaba.cola.statemachine.State; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -19,4 +21,12 @@ public static State getState(Map> stateMap, } return state; } + public static List> getStates(Map> stateMap, S ... stateIds) { + List> result = new ArrayList<>(); + for (S stateId : stateIds) { + State state = getState(stateMap, stateId); + result.add(state); + } + return result; + } } diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateImpl.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateImpl.java index 98207a4bd..7d5876156 100644 --- a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateImpl.java +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateImpl.java @@ -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; @@ -35,6 +36,17 @@ public Transition addTransition(E event, State target, Transitio return newTransition; } + @Override + public List> addTransitions(E event, List> targets, TransitionType transitionType) { + List> result = new ArrayList<>(); + for (State target : targets) { + Transition secTransition = addTransition(event, target, transitionType); + result.add(secTransition); + } + + return result; + } + @Override public List> getEventTransitions(E event) { return eventTransitions.get(event); diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateMachineImpl.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateMachineImpl.java index b930216f4..dbfd8dd87 100644 --- a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateMachineImpl.java +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/StateMachineImpl.java @@ -1,5 +1,6 @@ package com.alibaba.cola.statemachine.impl; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -57,6 +58,23 @@ public S fireEvent(S sourceStateId, E event, C ctx) { return transition.transit(ctx, false).getId(); } + @Override + public List fireParallelEvent(S sourceState, E event, C context) { + isReady(); + List> transitions = routeTransitions(sourceState, event, context); + List 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 transition : transitions) { + S id = transition.transit(context, false).getId(); + result.add(id); + } + return result; + } private Transition routeTransition(S sourceStateId, E event, C ctx) { State sourceState = getState(sourceStateId); @@ -79,6 +97,25 @@ private Transition routeTransition(S sourceStateId, E event, C ctx) { return transit; } + private List> routeTransitions(S sourceStateId, E event, C context) { + State sourceState = getState(sourceStateId); + List> result = new ArrayList<>(); + List> transitions = sourceState.getEventTransitions(event); + if (transitions == null || transitions.size() == 0) { + return null; + } + + for (Transition transition : transitions) { + Transition 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); diff --git a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineTest.java b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineTest.java index cbc39d423..c20997edd 100644 --- a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineTest.java +++ b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineTest.java @@ -12,6 +12,8 @@ import org.junit.Assert; import org.junit.Test; +import java.util.List; + /** * StateMachineTest * @@ -210,6 +212,32 @@ public void testMultiThread() { } } + @Test + public void testParallel(){ + StateMachineBuilder 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 stateMachine = builder.build("ParallelMachine"); + System.out.println(stateMachine.generatePlantUML()); + List 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 checkCondition() { return new Condition() {