Внутреннее действие перехода Spring Statemachine после объединения не вызывается - PullRequest
0 голосов
/ 03 марта 2019

Я пытаюсь настроить конечный автомат с fork и join.После присоединения я хотел бы вызвать действие в состоянии присоединения, используя внутренний переход.Проблема в том, что действие, настроенное для withInternal(), не запускается.Я попытался взломать .guard(context -> true), и я также играл с .timer() и .timerOnce(), но он тоже не работал.

Вот состояния конфигурации:

private void configureStates(StateMachineBuilder.Builder<String, String> builder) throws Exception {
        builder.configureStates()
                .withStates()
                .initial("A")

                .fork("B")
                .join("C")

                .state("A")
                .state("B_")
                .state("C")
                .state("D")
                .state("E")
                .and()

                .withStates()
                .parent("B_")
                .initial("B1")
                .end("C1")
                .and()

                .withStates()
                .parent("B_")
                .initial("B2")
                .end("C2")
                .and()

                .withStates()
                .parent("B_")
                .initial("B3")
                .end("C3")

                .end("E");
    }

Конфигурация переходов:

private void configureTransitions(StateMachineBuilder.Builder<String, String> builder) throws Exception {
        builder.configureTransitions()
                .withExternal()
                .source("A")
                .target("B")
                .event("E0")
                .action(context -> log.info("From A to B"))
                .and()

                .withInternal()
                .source("B")
                .guard(stateContext -> true)
                .action(context -> log.info("At B"))
                .timerOnce(50)
                .and()

                .withFork()
                .source("B")
                .target("B_")
                .and()

                .withExternal()
                .source("B1")
                .target("C1")
                .event("E1")
                .and()

                .withExternal()
                .source("B2")
                .target("C2")
                .event("E2")
                .and()

                .withExternal()
                .source("B3")
                .target("C3")
                .and()

                .withExternal()
                .source("C3")
                .target("A")
                .event("E3")
                .and()

                .withJoin()
                .source("B_")
                .target("C")
                .and()

                .withInternal()
                .source("C")
                .guard(context -> true)
                .action(context -> log.info("At C"))
                .timerOnce(50)
                .state("C")
                .and()

                .withExternal()
                .source("C")
                .target("D")
                .action(context -> log.info("At D"))
                .and()

                .withInternal()
                .source("D")
                .guard(stateContext -> true)
                .action(stateContext -> log.info("At internal D"))
                .timer(10)
                .and()

                .withExternal()
                .source("D")
                .event("E4")
                .target("E");
    }

Я также добавил слушателя к конечному автомату:

private StateMachineListener<String, String> listener() {
        return new StateMachineListenerAdapter<String, String>() {
            @Override
            public void stateChanged(State<String, String> from, State<String, String> to) {
                log.info("State transited from [{}] to [{}]",
                        from == null ? null : from.getId(),
                        to == null ? null : to.getId());
            }
        };
    }

И окончательная конфигурация:

private StateMachine<String, String> buildMachine() throws Exception {
        StateMachineBuilder.Builder<String, String> builder = StateMachineBuilder.builder();

        builder.configureConfiguration()
                .withConfiguration()
                .listener(listener())
                .autoStartup(true);

        configureStates(builder);

        configureTransitions(builder);

        return builder.build();
    }

Проблемазаключается в том, что ни одно из внутренних действий перехода не вызывается.

Я создал небольшой тест для данной конфигурации:

@Test
    public void testForkJoin() throws Exception {
        StateMachine<String, String> machine = buildMachine();

        StateMachineTestPlan<String, String> plan = StateMachineTestPlanBuilder.<String, String>builder()
                .defaultAwaitTime(3)
                .stateMachine(machine)

                .step()
                .expectStates("A")
                .and()

                .step()
                .sendEvent("E0")
                .expectStates("B_", "B1", "B2", "C3")
                .and()

                .step()
                .sendEvent("E1")
                .expectStates("B_", "C1", "B2", "C3")
                .and()

                .step()
                .sendEvent("E3")
                .expectState("A")
                .and()

                .step()
                .sendEvent("E0")
                .expectStates("B_", "B1", "B2", "C3")
                .and()

                .step()
                .sendEvent("E1")
                .expectStates("B_", "C1", "B2", "C3")
                .and()

                .step()
                .sendEvent("E2")
                .expectStates("D")
                .and()

                .step()
                .sendEvent("E4")
                .expectState("E")
                .and()

                .build();

        plan.test();
    }

В качестве обходного пути я добавил несколько внешних переходов (из C до D), но на самом деле я хотел бы опустить состояние D и перейти непосредственно к E, выполнив существующие действия как внутреннее действие перехода.

1 Ответ

0 голосов
/ 04 марта 2019

Я бы хотел опустить состояние D и перейти непосредственно к E, выполнив существующие действия как внутреннее переходное действие.

Краткий ответ: Вы можете 't.

Псевдосостояния Fork / Join не должны вводить спецификацию поведения (например, действие).Fork / Join используются только для моделирования параллельных операций (fork) и синхронизации (join) в SM (переходные псевдосостояния).

Реализация Spring State Machine соответствует спецификации UML и потомуиз этих действий, связанных с fork / join, не выполняются.

Действия связаны либо с конкретным переходом, либо с состоянием.

Действия, связанные с переходами:

При выполнении JOIN выможет иметь N (> = 2) источников (J1E, J2E - заключительные этапы этого другого региона), поэтому можно определить различные действия при переходе от J1E к этапу JOIN (action = A1) и из J2E в этап JOIN (action =A2).

Действия, связанные с состоянием:

Если у вас есть общее действие, которое необходимо выполнить после синхронизации параллельных операций, вы можете определить его как часть следующего перехода (например,Я верю в ваш случай SM, когда вы переходите с C на D).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...