diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/config/HistoryConfig.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/config/HistoryConfig.java index 40918ca81..cd0b2826c 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/config/HistoryConfig.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/config/HistoryConfig.java @@ -1,18 +1,22 @@ package ru.spcex.clearing.backendapi.config; +import java.util.LinkedList; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import ru.spcex.clearing.backendapi.controller.queue.history.condition.HistorySubscription; -import ru.spcex.clearing.backendapi.controller.queue.history.condition.specific.*; +import ru.spcex.clearing.backendapi.controller.queue.history.condition.specific.ClearingDateFromCondition; +import ru.spcex.clearing.backendapi.controller.queue.history.condition.specific.ClearingDateToCondition; +import ru.spcex.clearing.backendapi.controller.queue.history.condition.specific.CreatedFromCondition; +import ru.spcex.clearing.backendapi.controller.queue.history.condition.specific.CreatedToCondition; +import ru.spcex.clearing.backendapi.controller.queue.history.condition.specific.TradingDateFromCondition; +import ru.spcex.clearing.backendapi.controller.queue.history.condition.specific.TradingDateToCondition; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.platform.classes.base.SpcexObjectBase; import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; -import java.util.LinkedList; -import java.util.List; - @Configuration public class HistoryConfig { @@ -179,7 +183,7 @@ public class HistoryConfig { private HistorySubscription session() { HistorySubscription sbscr = new HistorySubscription(); - sbscr.setDestination("session"); + sbscr.setDestination("sessions"); sbscr.setSearchProxyMapName(IMDGDistributedNames.Map_SearchSession); sbscr.setFullHistoryMapName(IMDGDistributedNames.Map_Session); sbscr.setConditions(List.of( diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/config/RegistriesFilterConfig.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/config/RegistriesFilterConfig.java index 880e4522f..186f6b8d4 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/config/RegistriesFilterConfig.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/config/RegistriesFilterConfig.java @@ -40,6 +40,7 @@ public class RegistriesFilterConfig { predicateBuilder.regex("registryCode", "^[OT].*"), predicateBuilder.in("registryStatus", Arrays.asList( RegistryStatus.PROC.getKey(), + RegistryStatus.POOL.getKey(), RegistryStatus.MNG.getKey(), RegistryStatus.SPLT.getKey()).toArray(new String[0])), predicateBuilder.greatEqual("settlementDate", LocalDate.now())) diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/action/InclusionToPoolAction.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/action/InclusionToPoolAction.java index 86234ee6d..b0566036d 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/action/InclusionToPoolAction.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/action/InclusionToPoolAction.java @@ -203,7 +203,8 @@ public class InclusionToPoolAction extends AbstractSessionActionForOkErrorHandli return rgsPb.or( rgsPb.equals("sessionType", SessionType.FINL.getKey()), rgsPb.equals("sessionType", SessionType.MEDM.getKey()), - rgsPb.equals("sessionType", SessionType.XDEP.getKey()) + rgsPb.equals("sessionType", SessionType.XDEP.getKey()), + rgsPb.equals("sessionType", SessionType.UNIT.getKey()) ); } else if (SessionType.PAYM.equals(sessionType)) { return rgsPb.or( diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/action/ObligationAdmissionAction.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/action/ObligationAdmissionAction.java index fdf71e069..aacc303f1 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/action/ObligationAdmissionAction.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/action/ObligationAdmissionAction.java @@ -4,9 +4,10 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -80,16 +81,16 @@ public class ObligationAdmissionAction extends AbstractSessionActionForOkErrorHa .collect(Collectors.groupingBy(registry -> new GroupRgsKey(registry.getGroupId(), registry.getMarket()))); log.info("found {} ({} groups) registries with sessionId {}", registries.size(), byGroups.size(), sessionId); Map rgsToUpdate = new HashMap<>(); - List errs = new ArrayList<>(); + Set errs = new HashSet<>(); List groupErrors = new ArrayList<>(); for (Map.Entry> grpEntry : byGroups.entrySet()) { List rgsGroup = grpEntry.getValue(); for (Registry rgs : rgsGroup) { IValidator validator = valFor(rgs); - Optional error = validator.tillFirstError(); - error.ifPresent(e -> { + Collection errors = validator.validateAll(); + errors.forEach(e -> { groupErrors.add(e); - errs.add(new RgsErr(rgs, messageResolver.resolve(e))); + errs.add(new RgsErr(rgs, messageResolver.resolve(e), e.getSubject())); }); } if (!groupErrors.isEmpty()) { @@ -110,7 +111,7 @@ public class ObligationAdmissionAction extends AbstractSessionActionForOkErrorHa } ctx.getExtendedState().getVariables().put(DataEnum.obligationAdmissionStashedRgs, rgsToUpdate); - ctx.getExtendedState().getVariables().put(DataEnum.erroneousRegistries, errs); + ctx.getExtendedState().getVariables().put(DataEnum.erroneousRegistries, new ArrayList<>(errs)); // if (wasNack) { // } else { // registryImdg.putAll(rgsToUpdate); diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/model/RgsErr.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/model/RgsErr.java index ecb83ebd9..c90558fcd 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/model/RgsErr.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/state/model/RgsErr.java @@ -1,16 +1,25 @@ package ru.spcex.clearing.session.state.model; +import java.util.Objects; import ru.clearing.classes.statics.data.registry.Registry; +import ru.spcex.platform.utils.enumeration.IEnumId; public class RgsErr { private Registry rgs; private String err; + private IEnumId subj; public RgsErr(Registry rgs, String err) { this.rgs = rgs; this.err = err; } + public RgsErr(Registry rgs, String err, IEnumId subj) { + this.rgs = rgs; + this.err = err; + this.subj = subj; + } + public Registry getRgs() { return rgs; } @@ -26,4 +35,26 @@ public class RgsErr { public void setErr(String err) { this.err = err; } + + /** + * будут коллизии при большом количестве ошибок на один ТКР + */ + @Override + public int hashCode() { + return Long.hashCode(rgs.getTradingClearingRegistryId()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof RgsErr other)) return false; + boolean meaningEqual; + if (subj != null && other.subj != null) { + meaningEqual = subj.equals(other.subj); + } else { + meaningEqual = Objects.equals(err, other.err); + } + return rgs.getTradingClearingRegistryId().equals(other.rgs.getTradingClearingRegistryId()) + && meaningEqual; + } } 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; + } +} diff --git a/clearing-parent/db-scripts/src/main/resources/db/DICTIONARIES.sql b/clearing-parent/db-scripts/src/main/resources/db/DICTIONARIES.sql index ef5a988a8..b81319a74 100644 --- a/clearing-parent/db-scripts/src/main/resources/db/DICTIONARIES.sql +++ b/clearing-parent/db-scripts/src/main/resources/db/DICTIONARIES.sql @@ -1056,4 +1056,4 @@ INSERT INTO ERROR_CODE_DICTIONARY(ID, CODE, NAME) values (10001, 'TRDI', 'Сде /* Business objects */ -INSERT INTO DB_VERSION(ID, DICTIONARY_VERSION) values (1, '3.18.0.99') ON CONFLICT (ID) DO UPDATE SET DICTIONARY_VERSION = EXCLUDED.DICTIONARY_VERSION +INSERT INTO DB_VERSION(ID, DICTIONARY_VERSION) values (1, '3.19.0.100') ON CONFLICT (ID) DO UPDATE SET DICTIONARY_VERSION = EXCLUDED.DICTIONARY_VERSION