Merge remote-tracking branch 'origin/spring-state-machine-template-v2' into spring-state-machine-template-v2

This commit is contained in:
ialbert 2025-07-03 19:14:07 +03:00
commit 1ab524aacd
2 changed files with 273 additions and 5 deletions

View file

@ -0,0 +1,269 @@
package ru.spcex.clearing.config.state_machine_2.specific;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.function.Supplier;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
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.guard.Guard;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import ru.clearing.classes.statics.data.execution.ExecutionFond;
import ru.clearing.classes.statics.data.misc.Session;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.session.stage.TaskType;
import ru.spcex.clearing.session.state.DataEnum;
import ru.spcex.clearing.session.state.SsnEvent;
import ru.spcex.clearing.session.state.action.AgainReviseStage3Action;
import ru.spcex.clearing.session.state.action.CompoundDealsPrepareAction;
import ru.spcex.clearing.session.state.action.CreateSessionAction;
import ru.spcex.clearing.session.state.action.DealsPrepareAction;
import ru.spcex.clearing.session.state.action.DiscardRegistriesAction;
import ru.spcex.clearing.session.state.action.FinishingSessionAction;
import ru.spcex.clearing.session.state.action.FormingPaymentInstructionAssetsAction;
import ru.spcex.clearing.session.state.action.InclusionToPoolAction;
import ru.spcex.clearing.session.state.action.InspectionObligationsV2Action;
import ru.spcex.clearing.session.state.action.ObligationAdmissionAction;
import ru.spcex.clearing.session.state.action.RequirementAndObligationCreationAction;
import ru.spcex.clearing.session.state.action.ReviseStage1Action;
import ru.spcex.clearing.session.state.action.SaveRegistriesAndContinueAction;
import ru.spcex.clearing.session.state.action.Sdf56Action;
import ru.spcex.clearing.session.state.guard.PaymentsWereCreatedGuard;
import ru.spcex.clearing.session.state.guard.PaymentsWereNotCreatedGuard;
import ru.spcex.clearing.session.state.guard.SdfGuard;
import ru.spcex.clearing.session.state.guard.SdfGuardExtractorAfterAgainRevise;
import ru.spcex.clearing.session.state.guard.SdfGuardExtractorAfterAssets;
import ru.spcex.clearing.session.state.guard.StashedRegistriesPresentGuard;
import ru.spcex.clearing.session.state.listener.MachineMonitoringListener;
import static ru.spcex.clearing.util.StateMachineUtil.*;
import ru.spcex.platform.classes.base.interfaces.ExecutionType;
import ru.spcex.platform.enumeration.Section;
import ru.spcex.platform.enumeration.SessionType;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
@Configuration("intermediateMkrSessionStateMachineFactoryConfig")
@EnableStateMachineFactory(name = "UNIT")
public class UnitedSessionStateMachineConfig
extends EnumStateMachineConfigurerAdapter<TaskType, SsnEvent> {
private final Imdg<Session> sessionImdg;
private final Sdf56Action sendSdf56Action;
private final ReviseStage1Action reviseStage1Action;
private final DealsPrepareAction dealsPrepareCurrency;
private final DealsPrepareAction dealsPrepareTRDT;
private final DealsPrepareAction dealsPrepareFinal;
private final RequirementAndObligationCreationAction reqAndOblAction;
private final ObligationAdmissionAction obligationAdmissionAction;
private final InclusionToPoolAction inclusionToPoolAction;
private final InspectionObligationsV2Action inspectionObligationsV2Action;
private final FormingPaymentInstructionAssetsAction formingPaymentInstructionAssetsAction;
private final AgainReviseStage3Action againRevise;
private final SaveRegistriesAndContinueAction obligationAdmissionContinueAction;
private final FinishingSessionAction finishingSessionAction;
private final DiscardRegistriesAction discardOblAdmStash =
new DiscardRegistriesAction(DataEnum.obligationAdmissionStashedRgs);
private final StashedRegistriesPresentGuard oblAdmGuard = new StashedRegistriesPresentGuard(
DataEnum.obligationAdmissionStashedRgs
);
private final Guard<TaskType, SsnEvent> reviseSuccessGuard = guardCheckCtxForFlag(DataEnum.againReviseSuccess);
private final SessionType SESSION_TYPE = SessionType.UNIT;
public UnitedSessionStateMachineConfig(ImdgProvider imdgProvider,
Sdf56Action sendSdf56Action,
ReviseStage1Action reviseStage1Action,
ObjectFactory<DealsPrepareAction> dealsPrepareAction,
@Qualifier("requirementAndObligationCreationAction")
RequirementAndObligationCreationAction reqAndOblAction,
ObligationAdmissionAction obligationAdmissionAction,
InclusionToPoolAction inclusionToPoolAction,
InspectionObligationsV2Action inspectionObligationsV2Action,
FormingPaymentInstructionAssetsAction formingPaymentInstructionAssetsAction,
AgainReviseStage3Action againRevise,
SaveRegistriesAndContinueAction obligationAdmissionContinueAction,
FinishingSessionAction finishingSessionAction,
@Qualifier("marketCodesForCurr") Supplier<List<String>> marketCodesCurr,
@Qualifier("marketCodesForT0") Supplier<List<String>> marketCodesTrdt) {
this.sessionImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Session, Session.class);
this.sendSdf56Action = sendSdf56Action;
this.reviseStage1Action = reviseStage1Action;
this.dealsPrepareCurrency = dealsPrepareAction.getObject();
this.dealsPrepareTRDT = dealsPrepareAction.getObject();
this.dealsPrepareFinal = dealsPrepareAction.getObject();
this.reqAndOblAction = reqAndOblAction;
this.obligationAdmissionAction = obligationAdmissionAction;
this.inclusionToPoolAction = inclusionToPoolAction;
this.inspectionObligationsV2Action = inspectionObligationsV2Action;
this.formingPaymentInstructionAssetsAction = formingPaymentInstructionAssetsAction;
this.againRevise = againRevise;
this.obligationAdmissionContinueAction = obligationAdmissionContinueAction;
this.finishingSessionAction = finishingSessionAction;
{
Imdg<ExecutionFond> executionFondImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionFond, ExecutionFond.class);
dealsPrepareCurrency.searchForExecutions(ExecutionType.ExecutionCurrency);
ImdgPredicateBuilder pb = executionFondImdg.predicateBuilder();
dealsPrepareCurrency.addExecutionCurrencyCondition(pb.regex("settlementCode", "^T0.*$"));
dealsPrepareCurrency.addExecutionCurrencyCondition(pb.in("market", marketCodesCurr.get().toArray(new String[0])));
dealsPrepareTRDT.searchForExecutions(ExecutionType.ExecutionFond);
ImdgPredicateBuilder execFondPb = executionFondImdg.predicateBuilder();
dealsPrepareTRDT.addExecutionFondCondition(execFondPb.regex("settlementCode", "^T0.*$"));
dealsPrepareTRDT.addExecutionFondCondition(execFondPb.in("market", marketCodesTrdt.get().toArray(new String[0])));
dealsPrepareFinal.searchForExecutions(ExecutionType.ExecutionDeposit);
dealsPrepareFinal.addExecutionDepositCondition(pb.regex("firstLegSettlementCode", "^T0.*$"));
this.finishingSessionAction.setPr("1");
}
}
@Override
public void configure(StateMachineStateConfigurer<TaskType, SsnEvent> states) throws Exception {
states
.withStates()
.initial(TaskType.StartRevise, chain(
new CreateSessionAction(sessionImdg, SessionType.UNIT, Section.MULT),
sendSdf56Action))
.states(new HashSet<>(Arrays.asList(
TaskType.StartRevise,
TaskType.StartRevisePart1,
TaskType.DealsPrepare,
TaskType.RequirementsAndObligationsCreate,
TaskType.ObligationsAdmission,
TaskType.InclusionToPool,
TaskType.InspectionObligations,
TaskType.FormingPaymentInstruction,
TaskType.FinishingSession,
TaskType.EndStageNotification,
TaskType.PSEUDO_waitSdfAfterPaymentInstructions,
TaskType.PSEUDO_waitAfterObligationAdmissionError,
TaskType.EndStageNotification,
TaskType.AgainRevise,
TaskType.PSEUDO_waitSdfAfterAgainRevise
)))
.end(TaskType.EndStageNotification);
}
@Override
public void configure(StateMachineTransitionConfigurer<TaskType, SsnEvent> transitions) throws Exception {
transitions
.withExternal()
.event(SsnEvent.SDF_57)
.source(TaskType.StartRevise).target(TaskType.StartRevisePart1)
.action(reviseStage1Action)
.and()
.withExternal()
.source(TaskType.StartRevisePart1).target(TaskType.DealsPrepare)
.action(
chain(
dealsPrepareCurrency, new CompoundDealsPrepareAction(ExecutionType.ExecutionCurrency),
dealsPrepareFinal, new CompoundDealsPrepareAction(ExecutionType.ExecutionDeposit),
dealsPrepareTRDT, new CompoundDealsPrepareAction(ExecutionType.ExecutionFond))
)
.and()
.withExternal()
.source(TaskType.DealsPrepare).target(TaskType.RequirementsAndObligationsCreate)
.action(reqAndOblAction)
.and()
.withExternal()
.source(TaskType.RequirementsAndObligationsCreate).target(TaskType.ObligationsAdmission)
.action(obligationAdmissionAction)
.and()
.withExternal()
.source(TaskType.InclusionToPool).target(TaskType.InspectionObligations)
.action(inspectionObligationsV2Action)
.and()
.withExternal()
.source(TaskType.InspectionObligations).target(TaskType.FormingPaymentInstruction)
.action(formingPaymentInstructionAssetsAction)
.and()
.withExternal()
.source(TaskType.PSEUDO_waitSdfAfterPaymentInstructions)
.target(TaskType.AgainRevise)
.guard(new SdfGuard(SdfGuardExtractorAfterAssets.instance))
.action(againRevise)
.and()
.withExternal()
.source(TaskType.PSEUDO_waitSdfAfterAgainRevise)
.target(TaskType.AgainRevise)
.guard(new SdfGuard(SdfGuardExtractorAfterAgainRevise.instance))
.action(againRevise);
sourceObligationAdmission(transitions);
sourcePseudoAfterOAError(transitions);
sourceFormingPaymentInstruction(transitions);
sourceAgainRevise(transitions);
}
private void sourceObligationAdmission(StateMachineTransitionConfigurer<TaskType, SsnEvent> transitions) throws Exception {
transitions
.withExternal()
.source(TaskType.ObligationsAdmission)
.target(TaskType.PSEUDO_waitAfterObligationAdmissionError)
.guard(oblAdmGuard)
.and()
.withExternal()
.source(TaskType.ObligationsAdmission).target(TaskType.InclusionToPool)
.guard(invert(oblAdmGuard))
.action(chain(obligationAdmissionContinueAction, inclusionToPoolAction));
}
private void sourcePseudoAfterOAError(StateMachineTransitionConfigurer<TaskType, SsnEvent> transitions) throws Exception {
transitions
.withExternal()
.source(TaskType.PSEUDO_waitAfterObligationAdmissionError).target(TaskType.InclusionToPool)
.action(chain(obligationAdmissionContinueAction, inclusionToPoolAction))
.event(SsnEvent.CONTINUE)
.and()
.withExternal()
.source(TaskType.PSEUDO_waitAfterObligationAdmissionError).target(TaskType.ObligationsAdmission)
.action(chain(discardOblAdmStash, obligationAdmissionAction))
.event(SsnEvent.REPEAT);
}
private void sourceFormingPaymentInstruction(StateMachineTransitionConfigurer<TaskType, SsnEvent> transitions) throws Exception {
transitions
//если не создалось paymentInstruction'ов
.withExternal()
.source(TaskType.FormingPaymentInstruction)
.target(TaskType.AgainRevise)
.guard(PaymentsWereNotCreatedGuard.instance)
.action(againRevise)
.and()
//если создались paymentInstruction, переходим в режим ожидания
.withExternal()
.source(TaskType.FormingPaymentInstruction)
.target(TaskType.PSEUDO_waitSdfAfterPaymentInstructions)
.guard(PaymentsWereCreatedGuard.instance);
}
private void sourceAgainRevise(StateMachineTransitionConfigurer<TaskType, SsnEvent> transitions) throws Exception {
transitions
.withExternal()
.source(TaskType.AgainRevise)
.target(TaskType.FinishingSession)
.action(finishingSessionAction)
.guard(reviseSuccessGuard)
.and()
.withExternal()
.source(TaskType.AgainRevise)
.target(TaskType.PSEUDO_waitSdfAfterAgainRevise)
.guard(invert(reviseSuccessGuard));
}
@Override
public void configure(StateMachineConfigurationConfigurer<TaskType, SsnEvent> config) throws Exception {
StateMachineListenerAdapter<TaskType, SsnEvent> loggingChangeStateListener
= new MachineMonitoringListener(SESSION_TYPE.getKey());
config
.withConfiguration()
.machineId(SESSION_TYPE.getKey())
.listener(loggingChangeStateListener);
}
}

View file

@ -1,5 +1,6 @@
package ru.spcex.clearing.util;
import java.util.List;
import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.action.Action;
@ -24,11 +25,9 @@ public class StateMachineUtil {
return context -> !guard.evaluate(context);
}
public static <S, A> Action<S, A> chain(Action<S, A> a, Action<S, A> b) {
return context -> {
a.execute(context);
b.execute(context);
};
@SafeVarargs
public static <S, A> Action<S, A> chain(Action<S, A>... a) {
return context -> List.of(a).forEach(action -> action.execute(context));
}