diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/StateMachineTest.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/StateMachineTest.java index 14cc43f3d..c51d59cea 100644 --- a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/StateMachineTest.java +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/StateMachineTest.java @@ -1,120 +1,105 @@ package ru.spcex.clearing.session.teststate; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.config.StateMachineFactory; import ru.spcex.clearing.session.stage.TaskType; import ru.spcex.clearing.session.state.SsnEvent; -import ru.spcex.clearing.session.teststate.config.TestStateMachineConfig; +import ru.spcex.clearing.session.teststate.config.SmpState; +import ru.spcex.clearing.session.teststate.config.TestCurrStateMachineConfig; +import ru.spcex.clearing.session.teststate.config.TestSimpleStateMachineConfig; +import ru.spcex.clearing.session.teststate.config.TestSimpleStateMachineInterceptorConfig; +import ru.spcex.clearing.session.teststate.config.TestSimpleStateMachineRestoreConfig; import ru.spcex.clearing.session.teststate.config.TestStateMachineExecutorsConfig; +@EnabledIfSystemProperty(named = "ru.spcex.run.manual.tests", matches = "true") @SpringBootTest(classes = { - TestStateMachineConfig.class, + TestCurrStateMachineConfig.class, + TestSimpleStateMachineConfig.class, + TestSimpleStateMachineInterceptorConfig.class, + TestSimpleStateMachineRestoreConfig.class, TestStateMachineExecutorsConfig.class }) class StateMachineTest { private final Logger log = LoggerFactory.getLogger(getClass()); @Autowired - private StateMachineFactory stateMachineFactory; + @Qualifier("currTestMachine") + private StateMachineFactory currStateMachineFactory; - private StateMachine stateMachine; + @Autowired + @Qualifier("simpleTestMachineGuard") + private StateMachineFactory smpStateMachineGuardFactory; + @Autowired + @Qualifier("simpleTestMachineInterceptor") + private StateMachineFactory smpStateMachineInterceptorFactory; - @BeforeEach - public void setup() { - // Create a new state machine for each test - stateMachine = stateMachineFactory.getStateMachine(); + @Autowired + @Qualifier("testRestoredStateMachine") + private StateMachine restoredStateMachine; + + @Test + void testCurrency() { + StateMachine stateMachine = currStateMachineFactory.getStateMachine(); + addInterceptor(stateMachine); stateMachine.start(); + + log.debug("test started"); + stateMachine.sendEvent(SsnEvent.SDF_57); + log.info("Middle SM in state: {}", stateMachine.getState().getId());; + stateMachine.sendEvent(SsnEvent.SDF_57); + stateMachine.sendEvent(SsnEvent.SDF_04); + sleepForNSec(5); + log.info("End SM in state: {}", stateMachine.getState().getId());; } @Test - void test() { - log.debug("test started"); -// stateMachine -// .getStateMachineAccessor() -// .doWithRegion(function -> function.addStateMachineInterceptor( -// new StateMachineInterceptorAdapter<>() { -// @Override -// public Message preEvent(Message message, StateMachine stateMachine) { -// Event payload = message.getPayload(); -// log.info("INTERCEPTOR preEvent catched event {}", payload); -// return super.preEvent(message, stateMachine); -// } -// -// @Override -// public void preStateChange(org.springframework.statemachine.state.State state, Message message, Transition transition, StateMachine stateMachine, StateMachine rootStateMachine) { -// log.info("INTERCEPTOR preStateChange catched"); -// super.preStateChange(state, message, transition, stateMachine, rootStateMachine); -// } -// -// @Override -// public void postStateChange(org.springframework.statemachine.state.State state, Message message, Transition transition, StateMachine stateMachine, StateMachine rootStateMachine) { -// log.info("INTERCEPTOR postStateChange catched"); -// super.postStateChange(state, message, transition, stateMachine, rootStateMachine); -// } -// -// @Override -// public StateContext preTransition(StateContext stateContext) { -// log.info("INTERCEPTOR preTransition catched"); -// org.springframework.statemachine.state.State target = stateContext.getTarget(); -// //if (target.getId().equals(State.continueRevise)) { -// // IllegalStateException ex = new IllegalStateException("pre transition interceptor exception!!!"); -// // stateContext.getStateMachine().setStateMachineError(ex); -// // throw ex; -// //} -// return super.preTransition(stateContext); -// } -// -// @Override -// public StateContext postTransition(StateContext stateContext) { -// log.info("INTERCEPTOR postTransition catched"); -// return super.postTransition(stateContext); -// } -// -// @Override -// public Exception stateMachineError(StateMachine stateMachine, Exception exception) { -// log.info("INTERCEPTOR error caught!!!"); -// return exception; -// } -// })); + void testSmpGuard() { + StateMachine stateMachine = smpStateMachineGuardFactory.getStateMachine(); + addInterceptor(stateMachine); + stateMachine.start(); - // stateMachine.sendEvent(SsnEvent.); -// try { -// Thread.sleep(5000); -// } catch (InterruptedException e) { -// throw new RuntimeException(e); -// } -// stateMachine.sendEvent(Event.SDF_01); -// stateMachine.sendEvent(Event.SDF_04); -// stateMachine.sendEvent(Event.SDF_57); -// try { -// Thread.sleep(10000); -// } catch (InterruptedException e) { -// throw new RuntimeException(e); -// } -// stateMachine.sendEvent(Event.continueRevise); -// log.info("'ve send a continueRevise"); -// try { -// Thread.sleep(100010); -// } catch (InterruptedException e) { -// throw new RuntimeException(e); -// } -// log.info("FIRST STOP"); -// stateMachine.stop(); -// log.info("SECOND STOP"); -// stateMachine.stop(); - sleepForNSec(5); + log.debug("test started"); stateMachine.sendEvent(SsnEvent.SDF_57); + log.info("Middle SM in state: {}", stateMachine.getState().getId());; + stateMachine.sendEvent(SsnEvent.SDF_04); sleepForNSec(5); - stateMachine.sendEvent(SsnEvent.CONTINUE); - sleepForNSec(5); - log.info("So. We end with SM in state: {}", stateMachine.getState().getId());; + log.info("End SM in state: {}", stateMachine.getState().getId());; + } + + @Test + void testSmpInterceptor() { + StateMachine stateMachine = smpStateMachineInterceptorFactory.getStateMachine(); + addInterceptor(stateMachine); + stateMachine.start(); + + log.debug("test started"); + sleepForNSec(10); + log.info("End SM in state: {}", stateMachine.getState().getId());; + } + + @Test + void testRestoredSmp() { + addInterceptor(restoredStateMachine); + restoredStateMachine.start(); + + log.debug("test started"); + sleepForNSec(10); + log.info("End SM in state: {}", restoredStateMachine.getState().getId());; + } + + private static void addInterceptor(StateMachine sm) { + sm.getStateMachineAccessor() + .doWithAllRegions( + acs -> acs.addStateMachineInterceptor(new TestStateMachineInterceptorAdapter2<>()) + ); } public static void sleepForNSec(int i) { diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/TestStateMachineInterceptorAdapter2.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/TestStateMachineInterceptorAdapter2.java new file mode 100644 index 000000000..a9bac6cee --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/TestStateMachineInterceptorAdapter2.java @@ -0,0 +1,57 @@ +package ru.spcex.clearing.session.teststate; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.messaging.Message; +import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.state.PseudoStateKind; +import org.springframework.statemachine.state.State; +import org.springframework.statemachine.support.StateMachineInterceptorAdapter; +import org.springframework.statemachine.transition.Transition; + +class TestStateMachineInterceptorAdapter2 extends StateMachineInterceptorAdapter { + private static final Logger log = LoggerFactory.getLogger(TestStateMachineInterceptorAdapter2.class); + + private static String target(Transition t) { + if (t == null) return null; + String source = t.getSource() != null ? String.valueOf(t.getSource().getId()) : "[unknown source]"; + String target = t.getTarget() != null ? String.valueOf(t.getTarget().getId()) : "[unknown target]"; + return "source %s, target %s".formatted(source, target); + } + + + @Override + public void postStateChange(State state, Message message, Transition transition, StateMachine stateMachine, StateMachine rootStateMachine) { + log.info("INTERCEPTOR postStateChange " + target(transition)); + if (state != null + && state.getId() != null + && state.getPseudoState() != null + && state.getPseudoState().getKind() != null + ) { + PseudoStateKind kind = state.getPseudoState().getKind(); + if (kind.equals(PseudoStateKind.END)) { + log.info("INTERCEPTOR postStateChange: {} is END state", state.getId()); + } + } + } + + @Override + public StateContext preTransition(StateContext stateContext) { + log.info("INTERCEPTOR preTransition " + target(stateContext.getTransition())); + return stateContext; + } + + @Override + public void preStateChange(State state, Message message, Transition transition, StateMachine stateMachine, StateMachine rootStateMachine) { + log.info("INTERCEPTOR preStateChange " + target(transition)); + } + + @Override + public StateContext postTransition(StateContext stateContext) { + log.info("INTERCEPTOR postTransition " + target(stateContext.getTransition())); + return stateContext; + } + + +} diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/SmpEvent.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/SmpEvent.java new file mode 100644 index 000000000..84a35ce4c --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/SmpEvent.java @@ -0,0 +1,6 @@ +package ru.spcex.clearing.session.teststate.config; + +public enum SmpEvent { + SDF_57, + SDF_04 +} diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/SmpState.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/SmpState.java new file mode 100644 index 000000000..33cab101e --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/SmpState.java @@ -0,0 +1,7 @@ +package ru.spcex.clearing.session.teststate.config; + +public enum SmpState { + Begin, + WaitForSdf, + Finish +} diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestStateMachineConfig.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestCurrStateMachineConfig.java similarity index 70% rename from clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestStateMachineConfig.java rename to clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestCurrStateMachineConfig.java index ce9f02fdc..34ceda028 100644 --- a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestStateMachineConfig.java +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestCurrStateMachineConfig.java @@ -20,16 +20,15 @@ import org.springframework.statemachine.listener.StateMachineListenerAdapter; import org.springframework.statemachine.transition.Transition; import ru.spcex.clearing.session.stage.TaskType; import ru.spcex.clearing.session.state.SsnEvent; -import ru.spcex.clearing.session.state.action.SdfReceivedAction; -import ru.spcex.clearing.session.state.guard.PaymentsWereCreatedGuard; -import ru.spcex.clearing.session.state.guard.SdfGuard; -import ru.spcex.clearing.session.state.guard.SdfGuardExtractorAfterAssets; +import ru.spcex.clearing.session.state.action.SdfReceivedActionV2; +import ru.spcex.clearing.session.state.guard.SdfGuardUtil; import static ru.spcex.clearing.util.StateMachineUtil.chain; +import ru.spcex.platform.enumeration.Section; import ru.spcex.platform.utils.log.ExceptionUtils; @Configuration -@EnableStateMachineFactory -public class TestStateMachineConfig extends EnumStateMachineConfigurerAdapter { +@EnableStateMachineFactory(name = "currTestMachine") +public class TestCurrStateMachineConfig extends EnumStateMachineConfigurerAdapter { private final Logger log = LoggerFactory.getLogger(getClass()); @Autowired @@ -44,6 +43,7 @@ public class TestStateMachineConfig extends EnumStateMachineConfigurerAdapter log.info("create session action"), context -> log.info("send sdf56 action"))) +// .state(TaskType.PSEUDO_waitSdfAfterPaymentInstructions, SsnEvent.ALL_SDF_RECEIVED) .states(new HashSet<>(Arrays.asList( TaskType.StartRevise, TaskType.StartRevisePart1, @@ -52,7 +52,6 @@ public class TestStateMachineConfig extends EnumStateMachineConfigurerAdapter log.info("reviseStage1Action")) + .action(act("reviseStage1Action")) .and() .withExternal() .source(TaskType.StartRevisePart1).target(TaskType.DealsPrepare) - .action(context -> log.info("dealsPrepareAction")) + .action(act("dealsPrepareAction")) .and() .withExternal() .source(TaskType.DealsPrepare).target(TaskType.RequirementsAndObligationsCreate) - .action(context -> log.info("reqAndOblAction")) + .action(act("reqAndOblAction")) .and() .withExternal() .source(TaskType.RequirementsAndObligationsCreate).target(TaskType.ObligationsAdmission) - .action(context -> log.info("obligationAdmissionAction")) - .and() - .withExternal() - .source(TaskType.ObligationsAdmission) - .target(TaskType.PSEUDO_waitAfterObligationAdmissionError) - .guard(context -> true) - .and() - .withExternal() - .source(TaskType.PSEUDO_waitAfterObligationAdmissionError).target(TaskType.InclusionToPool) - .action(chain(ctx -> log.info("obligationAdmissionContinueAction"), ctx -> log.info("inclusionToPoolAction"))) - .event(SsnEvent.CONTINUE) - .and() - .withExternal() - .source(TaskType.PSEUDO_waitAfterObligationAdmissionError).target(TaskType.ObligationsAdmission) - .action(chain(act("discardOblAdmStash"), act("obligationAdmissionAction"))) - .event(SsnEvent.REPEAT) - .and() - .withExternal() - .source(TaskType.ObligationsAdmission).target(TaskType.InclusionToPool) - .guard(context -> false) //invert(oblAdmGuard) - .action(chain(act("obligationAdmissionContinueAction"), act("inclusionToPoolAction"))) + .action(act("obligationAdmissionAction")) .and() .withExternal() .source(TaskType.InclusionToPool).target(TaskType.InspectionObligations) - .action(act("inspOblDepositReturnAction")) .action(act("inspectionObligationsV2Action")) .and() .withExternal() .source(TaskType.InspectionObligations).target(TaskType.FormingPaymentInstruction) - .action(act("formingPaymentInstructionReturnMkrAction")) .action(act("formingPaymentInstructionAssetsAction")) .and() - //если не создалось paymentInstruction'ов .withExternal() - .source(TaskType.FormingPaymentInstruction) - .target(TaskType.FinishingSession) - .guard(ctx -> true) //PaymentsWereNotCreatedGuard.instance - .action(act("finishingSessionAction")) - .and() - //если создались paymentInstruction, переходим в режим ожидания - .withExternal() - .source(TaskType.FormingPaymentInstruction) - .target(TaskType.PSEUDO_waitSdfAfterPaymentInstructions) - .guard(PaymentsWereCreatedGuard.instance) - .and() - .withExternal() - .source(TaskType.PSEUDO_waitSdfAfterPaymentInstructions) - .target(TaskType.FinishingSession) - .guard(new SdfGuard(SdfGuardExtractorAfterAssets.instance)) - .action(act("finishingSessionAction")) + .source(TaskType.PSEUDO_waitSdfAfterAgainRevise) + .target(TaskType.AgainRevise) + .guard(ctx -> true) + .action(act("againRevise")) .and() .withExternal() .source(TaskType.FinishingSession) .target(TaskType.EndStageNotification) .action(act("endStageNotificationAction")); - for (var event: EnumSet.of(SsnEvent.SDF_01, SsnEvent.SDF_57, SsnEvent.SDF_04)) { + sourceObligationAdmission(transitions); + sourcePseudoAfterOAError(transitions); + sourceFormingPaymentInstruction(transitions); + sourcePseudoWaitSdfAfterPaymentInstructions(transitions); + sourceAgainRevise(transitions); + } + + private void sourceObligationAdmission(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TaskType.ObligationsAdmission) + .target(TaskType.PSEUDO_waitAfterObligationAdmissionError) + .guard(ctx -> false) + .and() + .withExternal() + .source(TaskType.ObligationsAdmission).target(TaskType.InclusionToPool) + .guard(ctx -> true) + .action(chain(act("obligationAdmissionContinueAction"), act("inclusionToPoolAction"))); + } + + private void sourcePseudoAfterOAError(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TaskType.PSEUDO_waitAfterObligationAdmissionError).target(TaskType.InclusionToPool) + .action(chain(act("obligationAdmissionContinueAction"), act("inclusionToPoolAction"))) + .event(SsnEvent.CONTINUE) + .and() + .withExternal() + .source(TaskType.PSEUDO_waitAfterObligationAdmissionError).target(TaskType.ObligationsAdmission) + .action(chain(act("discardOblAdmStash"), act("obligationAdmissionAction"))) + .event(SsnEvent.REPEAT); + } + + private void sourceFormingPaymentInstruction(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + //если не создалось paymentInstruction'ов + .withExternal() + .source(TaskType.FormingPaymentInstruction) + .target(TaskType.AgainRevise) + .guard(ctx -> false) + .action(act("againRevise")) + .and() + //если создались paymentInstruction, переходим в режим ожидания + .withExternal() + .source(TaskType.FormingPaymentInstruction) + .target(TaskType.PSEUDO_waitSdfAfterPaymentInstructions) + .guard(ctx -> true); + } + + private void sourcePseudoWaitSdfAfterPaymentInstructions(StateMachineTransitionConfigurer transitions) throws Exception { +// EnumSet sdfs = SdfGuardUtil.bySectionAfter7Step(Section.MKR); +// transitions +// .withExternal() +// .source(TaskType.PSEUDO_waitSdfAfterPaymentInstructions) +// .target(TaskType.AgainRevise) +// .guard(new SdfSetGuard(sdfs)) +// .action(act("againRevise")); +// for (var event : sdfs) { +// transitions +// .withInternal() +// .source(TaskType.PSEUDO_waitSdfAfterPaymentInstructions) +// .event(event) +// .action(SdfReceivedAction.instance); +// } + + EnumSet sdfs = SdfGuardUtil.bySectionAfter7Step(Section.MKR); + SdfReceivedActionV2 sdfReceivedAction = new SdfReceivedActionV2<>(sdfs); + for (var event : sdfs) { transitions .withInternal() .source(TaskType.PSEUDO_waitSdfAfterPaymentInstructions) .event(event) - .action(SdfReceivedAction.instance); + .action(sdfReceivedAction); } + transitions.withExternal() + .source(TaskType.PSEUDO_waitSdfAfterPaymentInstructions) + .target(TaskType.EndStageNotification) + .event(SsnEvent.ALL_SDF_RECEIVED) + .action(context -> { + System.out.println("***** ALL SDF RECEIVED"); + log.info("***** ALL SDF RECEIVED"); + }); + } + + private void sourceAgainRevise(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TaskType.AgainRevise) + .target(TaskType.FinishingSession) + .action(act("finishingSessionAction")) + .guard(ctx -> true) + .and() + .withExternal() + .source(TaskType.AgainRevise) + .target(TaskType.PSEUDO_waitSdfAfterAgainRevise) + .guard(ctx -> false); } private Action act(String actionName) { @@ -209,7 +261,7 @@ public class TestStateMachineConfig extends EnumStateMachineConfigurerAdapter { + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Autowired + @Qualifier("myStateMachineTaskExecutor") + private TaskExecutor taskExecutor; + + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(SmpState.Begin, context -> log.info("Begin entry")) + .states(new HashSet<>(Arrays.asList( + SmpState.Begin, + SmpState.WaitForSdf + ))) + .end(SmpState.Finish); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(SmpState.Begin) + .target(SmpState.WaitForSdf) + .action(act("action Begin -> Wait for sdf")) + ; + + EnumSet sdfs = SdfGuardUtil.bySectionAfter7Step(Section.MKR); + SdfReceivedActionV2 sdfReceivedAction = new SdfReceivedActionV2<>(sdfs); + for (var event : sdfs) { + transitions + .withInternal() + .source(SmpState.WaitForSdf) + .event(event) + .action(sdfReceivedAction); + } + transitions.withExternal() + .source(SmpState.WaitForSdf) + .target(SmpState.Finish) + .event(SsnEvent.ALL_SDF_RECEIVED) + .action(context -> { + System.out.println("***** ALL SDF RECEIVED"); + log.info("***** ALL SDF RECEIVED"); + }); + } + + + private Action act(String actionName) { + return ctx -> log.info(actionName); + } + + @Override + public void configure(StateMachineConfigurationConfigurer config) throws Exception { + StateMachineListenerAdapter loggingChangeStateListener = new StateMachineListenerAdapter<>() { +// @Override +// public void stateEntered(org.springframework.statemachine.state.State state) { +// SmpState enteredState = state != null ? state.getId() : null; +// log.info(String.format("LISTENER stateEntered: %s", enteredState)); +// } + +// @Override +// public void eventNotAccepted(Message event) { +// SsnEvent payload = event != null ? event.getPayload() : null; +// log.info(String.format("LISTENER eventNotAccepted: %s", payload)); +// } + + @Override + public void transition(Transition transition) { + SmpState source = transition.getSource() != null ? transition.getSource().getId() : null; + SmpState target = transition.getTarget().getId(); + log.info("LISTENER transition: source {} target {}", + source, target); + } + +// @Override +// public void stateChanged(org.springframework.statemachine.state.State from, org.springframework.statemachine.state.State to) { +// SmpState source = from != null ? from.getId() : null; +// SmpState target = to.getId(); +// log.info("LISTENER stateChanged: source {} target {}", +// source, target); +// } + +// @Override +// public void stateExited(org.springframework.statemachine.state.State state) { +// SmpState whichOne = state != null ? state.getId() : null; +// log.info("LISTENER stateExited: {}", whichOne); +// } + +// @Override +// public void transitionEnded(Transition transition) { +// SmpState source = transition.getSource() != null ? transition.getSource().getId() : null; +// SmpState target = transition.getTarget().getId(); +// log.info("LISTENER transitionEnded: source {} target {}", +// source, target); +// } + + @Override + public void stateMachineError(StateMachine stateMachine, Exception exception) { + log.info("LISTENER stateMachineError: {}", (ExceptionUtils.getStackTrace(exception))); + } + +// @Override +// public void transitionStarted(Transition transition) { +// SmpState source = transition.getSource() != null ? transition.getSource().getId() : null; +// SmpState target = transition.getTarget().getId(); +// log.info("LISTENER transitionStarted: source {} target {}", +// source, target); +// } + }; + config + .withConfiguration() + .machineId("smp-test-machine") + .listener(loggingChangeStateListener) +// .taskExecutor(taskExecutor) + ; + + } +} diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestSimpleStateMachineInterceptorConfig.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestSimpleStateMachineInterceptorConfig.java new file mode 100644 index 000000000..ebc23e1fd --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestSimpleStateMachineInterceptorConfig.java @@ -0,0 +1,143 @@ +package ru.spcex.clearing.session.teststate.config; + +import java.util.Arrays; +import java.util.HashSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.action.Action; +import org.springframework.statemachine.config.EnableStateMachineFactory; +import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.listener.StateMachineListenerAdapter; +import org.springframework.statemachine.transition.Transition; +import ru.spcex.clearing.session.state.DataEnum; +import ru.spcex.clearing.session.state.SsnEvent; +import ru.spcex.platform.utils.log.ExceptionUtils; + +@Configuration +@EnableStateMachineFactory(name = "simpleTestMachineInterceptor") +public class TestSimpleStateMachineInterceptorConfig extends EnumStateMachineConfigurerAdapter { + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Autowired + @Qualifier("myStateMachineTaskExecutor") + private TaskExecutor taskExecutor; + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(SmpState.Begin, context -> log.info("Begin entry")) + .states(new HashSet<>(Arrays.asList( + SmpState.Begin, + SmpState.WaitForSdf + ))) + .end(SmpState.Finish); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(SmpState.Begin) + .target(SmpState.WaitForSdf) + .action(act("action Begin -> Wait for sdf")) + ; + + + transitions + .withExternal() + .source(SmpState.WaitForSdf) + .target(SmpState.Finish) + .guard(context -> { + log.info("guard check running..."); + return true; + }) + .action(context -> { + log.info("action WaitForSdf -> Finish for sdf"); + Object o = context.getExtendedState().get(DataEnum.sessionId, Long.class); + if (o != null) { + log.info("{} was not null: {}", DataEnum.sessionId, o); + } + }); + } + + + private Action act(String actionName) { + return ctx -> log.info(actionName); + } + + @Override + public void configure(StateMachineConfigurationConfigurer config) throws Exception { + StateMachineListenerAdapter loggingChangeStateListener = new StateMachineListenerAdapter<>() { +// @Override +// public void stateEntered(org.springframework.statemachine.state.State state) { +// SmpState enteredState = state != null ? state.getId() : null; +// log.info(String.format("LISTENER stateEntered: %s", enteredState)); +// } + +// @Override +// public void eventNotAccepted(Message event) { +// SsnEvent payload = event != null ? event.getPayload() : null; +// log.info(String.format("LISTENER eventNotAccepted: %s", payload)); +// } + + @Override + public void transition(Transition transition) { + SmpState source = transition.getSource() != null ? transition.getSource().getId() : null; + SmpState target = transition.getTarget().getId(); + log.info("LISTENER transition: source {} target {}", + source, target); + } + +// @Override +// public void stateChanged(org.springframework.statemachine.state.State from, org.springframework.statemachine.state.State to) { +// SmpState source = from != null ? from.getId() : null; +// SmpState target = to.getId(); +// log.info("LISTENER stateChanged: source {} target {}", +// source, target); +// } + +// @Override +// public void stateExited(org.springframework.statemachine.state.State state) { +// SmpState whichOne = state != null ? state.getId() : null; +// log.info("LISTENER stateExited: {}", whichOne); +// } + +// @Override +// public void transitionEnded(Transition transition) { +// SmpState source = transition.getSource() != null ? transition.getSource().getId() : null; +// SmpState target = transition.getTarget().getId(); +// log.info("LISTENER transitionEnded: source {} target {}", +// source, target); +// } + + @Override + public void stateMachineError(StateMachine stateMachine, Exception exception) { + log.info("LISTENER stateMachineError: {}", (ExceptionUtils.getStackTrace(exception))); + } + +// @Override +// public void transitionStarted(Transition transition) { +// SmpState source = transition.getSource() != null ? transition.getSource().getId() : null; +// SmpState target = transition.getTarget().getId(); +// log.info("LISTENER transitionStarted: source {} target {}", +// source, target); +// } + }; + config + .withConfiguration() + .machineId("smp-test-machine") +// .listener(loggingChangeStateListener) +// .taskExecutor(taskExecutor) + ; + + } +} diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestSimpleStateMachineRestoreConfig.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestSimpleStateMachineRestoreConfig.java new file mode 100644 index 000000000..3b1d3f80e --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/session/teststate/config/TestSimpleStateMachineRestoreConfig.java @@ -0,0 +1,41 @@ +package ru.spcex.clearing.session.teststate.config; + +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.config.StateMachineFactory; +import org.springframework.statemachine.support.DefaultExtendedState; +import org.springframework.statemachine.support.DefaultStateMachineContext; +import ru.spcex.clearing.session.state.DataEnum; +import ru.spcex.clearing.session.state.SsnEvent; + +@Configuration +public class TestSimpleStateMachineRestoreConfig { + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Autowired + @Qualifier("simpleTestMachineInterceptor") + private StateMachineFactory smpStateMachineInterceptorFactory; + + @Bean("testRestoredStateMachine") + public StateMachine restoredStateMachine() { + StateMachine sm = smpStateMachineInterceptorFactory.getStateMachine(); + sm.stop(); + DefaultExtendedState state = new DefaultExtendedState(); + Map vars = state.getVariables(); + vars.put(DataEnum.sessionId, 1L); + DefaultStateMachineContext ctx = new DefaultStateMachineContext<>( + SmpState.WaitForSdf, + null, + null, + state + ); + sm.getStateMachineAccessor().doWithAllRegions(a -> a.resetStateMachine(ctx)); + return sm; + } +}