diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/Transition.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/Transition.java index 5247fc40a..20a68b9a6 100644 --- a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/Transition.java +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/Transition.java @@ -28,6 +28,8 @@ public interface Transition{ void setEvent(E event); + TransitionType getType(); + void setType(TransitionType type); /** * Gets the target state of this 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..bf6086e06 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 @@ -21,7 +21,6 @@ public class StateMachineBuilderImpl implements StateMachineBuilder> stateMap = new ConcurrentHashMap<>(); - private final StateMachineImpl stateMachine = new StateMachineImpl<>(stateMap); private FailCallback failCallback = new NumbFailCallback<>(); @Override @@ -46,6 +45,7 @@ public void setFailCallback(FailCallback callback) { @Override public StateMachine build(String machineId) { + StateMachineImpl stateMachine = new StateMachineImpl<>(stateMap); stateMachine.setMachineId(machineId); stateMachine.setReady(true); stateMachine.setFailCallback(failCallback); 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..dd589a39c 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 @@ -1,7 +1,9 @@ package com.alibaba.cola.statemachine.impl; import com.alibaba.cola.statemachine.State; +import com.alibaba.cola.statemachine.Transition; +import java.util.HashMap; import java.util.Map; /** @@ -11,12 +13,26 @@ * @date 2020-02-08 4:23 PM */ public class StateHelper { - public static State getState(Map> stateMap, S stateId){ - State state = stateMap.get(stateId); - if (state == null) { - state = new StateImpl<>(stateId); - stateMap.put(stateId, state); - } - return state; + + private StateHelper() { + } + + public static State getState(Map> stateMap, S stateId) { + return stateMap.computeIfAbsent(stateId, StateImpl::new); + } + + static Map> cloneStateMap(Map> stateMap) { + Map> cloneStateMap = new HashMap<>(); + stateMap.forEach((stateId, state) -> { + State cloneState = getState(cloneStateMap, stateId); + state.getAllTransitions().forEach(transition -> { + State target = transition.getTarget(); + Transition cloneTransition = cloneState.addTransition(transition.getEvent(), + getState(cloneStateMap, target.getId()), transition.getType()); + cloneTransition.setCondition(transition.getCondition()); + cloneTransition.setAction(transition.getAction()); + }); + }); + return cloneStateMap; } } 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..2c2eade5a 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 @@ -30,7 +30,7 @@ public class StateMachineImpl implements StateMachine { private FailCallback failCallback; public StateMachineImpl(Map> stateMap) { - this.stateMap = stateMap; + this.stateMap = StateHelper.cloneStateMap(stateMap); } @Override diff --git a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/TransitionImpl.java b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/TransitionImpl.java index 3ea21e4fa..801b3f2e0 100644 --- a/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/TransitionImpl.java +++ b/cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/TransitionImpl.java @@ -47,6 +47,11 @@ public void setEvent(E event) { this.event = event; } + @Override + public TransitionType getType() { + return type; + } + @Override public void setType(TransitionType type) { this.type = type; diff --git a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineBuilderTest.java b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineBuilderTest.java new file mode 100644 index 000000000..ef83e8708 --- /dev/null +++ b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineBuilderTest.java @@ -0,0 +1,72 @@ +package com.alibaba.cola.test; + +import com.alibaba.cola.statemachine.Action; +import com.alibaba.cola.statemachine.StateMachine; +import com.alibaba.cola.statemachine.builder.StateMachineBuilder; +import com.alibaba.cola.statemachine.builder.StateMachineBuilderFactory; +import org.junit.Assert; +import org.junit.Test; + +/** + * StateMachineBuilderTest + * + * @author luozhenyu + * @date 2023-02-20 01:37 AM + */ +public class StateMachineBuilderTest { + + enum States { + STATE1, + STATE2, + STATE3 + } + + enum Events { + EVENT1, + EVENT2 + } + + static class Context { + } + + @Test + public void testReuseBuilder() { + StateMachineBuilder builder = StateMachineBuilderFactory.create(); + builder.externalTransition() + .from(States.STATE1) + .to(States.STATE2) + .on(Events.EVENT1) + .perform(doAction()); + StateMachine stateMachine1 = builder.build("TestReuseBuilder1"); + { + States target = stateMachine1.fireEvent(States.STATE1, Events.EVENT1, new Context()); + Assert.assertEquals(States.STATE2, target); + target = stateMachine1.fireEvent(States.STATE1, Events.EVENT2, new Context()); + Assert.assertEquals(States.STATE1, target); + } + + builder.externalTransition() + .from(States.STATE1) + .to(States.STATE3) + .on(Events.EVENT2) + .perform(doAction()); + StateMachine stateMachine2 = builder.build("TestReuseBuilder2"); + { + States target = stateMachine1.fireEvent(States.STATE1, Events.EVENT1, new Context()); + Assert.assertEquals(States.STATE2, target); + target = stateMachine1.fireEvent(States.STATE1, Events.EVENT2, new Context()); + Assert.assertEquals(States.STATE1, target); + + target = stateMachine2.fireEvent(States.STATE1, Events.EVENT1, new Context()); + Assert.assertEquals(States.STATE2, target); + target = stateMachine2.fireEvent(States.STATE1, Events.EVENT2, new Context()); + Assert.assertEquals(States.STATE3, target); + } + } + + private Action doAction() { + return (from, to, event, context) -> { + System.out.println("from:" + from + " to:" + to + " on:" + event); + }; + } +}