0

spring-statemachine で階層ステート マシンを構築しようとしています。それぞれが 2 つのサービスの状態を表す 2 つの直交状態を持つ必要があります。次のコードでは、簡単にするために状態の数を減らしていますが、それでも同じエラーが発生します。

public enum MachineState {
    BUFF,BUFF_OFFLINE, BUFF_ONLINE,
    CB,CB_OFFLINE,CB_ONLINE
}

public enum MachineEvent {
    BUFF_OFF,BUFF_ON,
    CB_OFF, CB_NORESP, BUFF_NORESP, CB_ON
}

@Configuration
@EnableStateMachine
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<MachineState, MachineEvent> {


    @Override
    public void configure(final StateMachineConfigurationConfigurer<MachineState, MachineEvent> config)
            throws Exception {
        config
            .withConfiguration()
            .autoStartup(true);
    }

    @Override
    public void configure(final StateMachineStateConfigurer<MachineState, MachineEvent> states)
            throws Exception {
        states
            .withStates()
                .initial(MachineState.BUFF)
                .and()
                .withStates()
                    .parent(MachineState.BUFF)
                    .initial(MachineState.BUFF_OFFLINE)
                    .state(MachineState.BUFF_ONLINE)
            .and()
            .withStates()
                .initial(MachineState.CB)
                .and()
                .withStates()
                    .parent(MachineState.CB)
                    .initial(MachineState.CB_OFFLINE)
                    .state(MachineState.CB_ONLINE)
            .and()
        ;
    }

    @Override
    public void configure(final StateMachineTransitionConfigurer<MachineState, MachineEvent> transitions)
            throws Exception {
        transitions
            .withExternal()
                .source(MachineState.BUFF_OFFLINE).target(MachineState.BUFF_ONLINE)
                .event(MachineEvent.BUFF_ON)
            .and()

            .withExternal()
                .source(MachineState.BUFF_ONLINE).target(MachineState.BUFF_OFFLINE)
                .event(MachineEvent.BUFF_OFF)
            .and()

            .withExternal()
                .source(MachineState.CB_OFFLINE).target(MachineState.CB_ONLINE)
                .event(MachineEvent.CB_ON)
            .and()

            .withExternal()
                .source(MachineState.CB_ONLINE).target(MachineState.CB_OFFLINE)
                .event(MachineEvent.CB_OFF)
            .and()

            .withInternal()
                .source(MachineState.CB)
                .event(MachineEvent.CB_NORESP)
            .and()

            .withInternal()
                .source(MachineState.BUFF)
                .event(MachineEvent.BUFF_NORESP)
            .and()
        ;
    }
}

まず、設定で何か間違ったことをしましたか?

私が得るエラーは次のとおりです

Caused by: java.lang.IllegalArgumentException: Source must be set
    at org.springframework.util.Assert.notNull(Assert.java:115) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.statemachine.transition.AbstractTransition.<init>(AbstractTransition.java:63) ~[spring-statemachine-core-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.statemachine.transition.AbstractInternalTransition.<init>(AbstractInternalTransition.java:35) ~[spring-statemachine-core-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.statemachine.transition.DefaultInternalTransition.<init>(DefaultInternalTransition.java:35) ~[spring-statemachine-core-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.statemachine.config.AbstractStateMachineFactory.buildMachine(AbstractStateMachineFactory.java:704) ~[spring-statemachine-core-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.statemachine.config.AbstractStateMachineFactory.getStateMachine(AbstractStateMachineFactory.java:189) ~[spring-statemachine-core-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.statemachine.config.AbstractStateMachineFactory.getStateMachine(AbstractStateMachineFactory.java:126) ~[spring-statemachine-core-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.statemachine.config.configuration.StateMachineConfiguration$StateMachineDelegatingFactoryBean.afterPropertiesSet(StateMachineConfiguration.java:154) ~[spring-statemachine-core-1.1.0.RELEASE.jar:1.1.0.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]

アプリケーションをデバッグしたところ、spring-statemachine-core AbstractStateMachineFactory buildMachine() で、stateMap に CB および BUFF 状態のいずれかが欠落していることがわかりました。最も奇妙な部分は、どの縫い目がランダムで、実際にはセット全体が含まれている場合があり、例外はありません。

両方の内部トランジションを削除してコードをデバッグしたところ、stateMap が不完全であっても (そして、欠落している状態からのトランジションがあったとしたら失敗していたはずです)、インスタンス化後のステート マシンは希望どおりに見えることがわかりました。あります。

何か案は?

サンプル プロジェクトhttps://www.dropbox.com/s/qlarppnma0dq9ai/statemachineerror.tar.gz?dl=0

4

1 に答える 1

0

したがって、私が望んでいたことを達成するには、内部遷移ではなく外部遷移を使用する必要がありました。これは、サブステートのいずれかで発生する可能性があり、リージョンを初期状態に戻すイベントです。

.withExternal()
    .source(MachineState.CB).target(MachineState.CB)
    .event(MachineEvent.CB_NORESP)
.and()
.withExternal()
    .source(MachineState.BUFF).target(MachineState.BUFF)
    .event(MachineEvent.BUFF_NORESP)
.and()

内部移行が進むべき道である場合、回避策も見つけました。バグの制限は、私のように内部遷移を使用したい場合、初期状態で直交領域を持つことができないことです。解決策は、2 つの新しい状態を導入し、最初の状態から 2 番目の状態への自動遷移を行い、2 番目の状態を 2 つの直交領域の親状態にすることでした。

@Configuration
@EnableStateMachine
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<MachineState, MachineEvent> {


    @Override
    public void configure(final StateMachineConfigurationConfigurer<MachineState, MachineEvent> config)
            throws Exception {
        config
            .withConfiguration()
            .autoStartup(true);
    }

    @Override
    public void configure(final StateMachineStateConfigurer<MachineState, MachineEvent> states)
            throws Exception {
        states
            .withStates()
                .initial(MachineState.INITIAL)
                .state(MachineState.INITIAL, init(), null)
                .state(MachineState.PARENT)
                .and()

                // Region 1 (BUFF)
                .withStates()
                    .parent(MachineState.PARENT)
                    .initial(MachineState.BUFF)
                    .and()
                    .withStates()
                        .parent(MachineState.BUFF)
                        .initial(MachineState.BUFF_OFFLINE)
                        .state(MachineState.BUFF_ONLINE)
                .and()

                // Region 2 (CB)
                .withStates()
                    .parent(MachineState.PARENT)
                    .initial(MachineState.CB)
                    .and()
                    .withStates()
                        .parent(MachineState.CB)
                        .initial(MachineState.CB_OFFLINE)
                        .state(MachineState.CB_ONLINE)
                .and()
        ;
    }

    @Override
    public void configure(final StateMachineTransitionConfigurer<MachineState, MachineEvent> transitions)
            throws Exception {
        transitions
            .withExternal()
                .source(MachineState.BUFF_OFFLINE).target(MachineState.BUFF_ONLINE)
                .event(MachineEvent.BUFF_ON)
            .and()

            .withExternal()
                .source(MachineState.BUFF_ONLINE).target(MachineState.BUFF_OFFLINE)
                .event(MachineEvent.BUFF_OFF)
            .and()

            .withExternal()
                .source(MachineState.CB_OFFLINE).target(MachineState.CB_ONLINE)
                .event(MachineEvent.CB_ON)
            .and()

            .withExternal()
                .source(MachineState.CB_ONLINE).target(MachineState.CB_OFFLINE)
                .event(MachineEvent.CB_OFF)
            .and()

            .withInternal()
                .source(MachineState.CB)
                .event(MachineEvent.CB_NORESP)
            .and()

            .withInternal()
                .source(MachineState.BUFF)
                .event(MachineEvent.BUFF_NORESP)
            .and()

            .withExternal()
                .source(MachineState.INITIAL).target(MachineState.PARENT)
                .event(MachineEvent.INIT)
            .and()
        ;
    }

    @Bean
    public Action<MachineState, MachineEvent> init() {
        return new Action<MachineState, MachineEvent>() {
            @Override
            public void execute(StateContext<MachineState, MachineEvent> context) {
                context.getStateMachine().sendEvent(MachineEvent.INIT);
            }
        };
    }
}
于 2016-09-01T14:12:57.293 に答える