微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

分层状态未保留在数据库中

如何解决分层状态未保留在数据库中

在持久化数据库之后,我一直在努力从数据库获取分层状态机的正确状态。父计算机具有两个状态(“ IN_ANALYSIS”,“ OPEN”),而IN_ANALYSIS状态具有子状态(“ IN_PROGRESS”,“ PENDING_SIGNOFF”,“ PENDING_SIGNOFF2”,“已完成”。

        @Override
        public void configure(StateMachinestateConfigurer<States,Events> states)
                throws Exception {
            states
                    .withStates()
                    .initial(States.IN_ANALYSIS)
                    .state(States.IN_ANALYSIS)
                    .state(States.OPEN)
                    .and()
                    .withStates()
                    .parent(States.IN_ANALYSIS)
                    .initial(States.IN_PROGRESS)
                    .state(States.IN_PROGRESS)
                    .state(States.PENDING_SIGNOFF)
                    .state(States.PENDING_SIGNOFF2)
                    .state(States.COMPLETED,closedEntryAction(),null);
        }

每当我将状态机置于诸如(PENDING_SIGNOFF,PENDING_SIGNOFF2)之类的中间子状态之一时,稍后再从数据库中再次获取它,则子状态会重置为初始状态(IN_PROGRESS )

我正在使用Spring State Machine框架提供的JPA持久性

    @Configuration
    @Profile("jpa")
    public static class JpaPersisterConfig {

        @Bean
        public StateMachineRuntimePersister<States,Events,String> stateMachineRuntimePersister(
                JpaStateMachineRepository jpaStateMachineRepository) {
            return new JpaPersistingStateMachineInterceptor<>(jpaStateMachineRepository);
        }
    }

并使用“ DefaultStateMachineservice”

@Configuration
    public static class ServiceConfig {



        @Bean
        public StateMachineservice<States,Events> stateMachineservice(
                StateMachineFactory<States,Events> stateMachineFactory,StateMachineRuntimePersister<States,String> stateMachineRuntimePersister) {
            return new DefaultStateMachineservice<States,Events>(stateMachineFactory,stateMachineRuntimePersister);
        }

    }

解决方法

Spring似乎将分层状态另存为Data Multi Persist示例中描述的状态机上下文。 尝试通过将嵌套状态标记为区域并设置区域ID来configure regions。然后您可以通过ID和区域ID请求状态机

StateMachine<States,Events> sm = defaultStateMachineService.acquireStateMachine(stateMachineId + "#" + regionId)
,

问题出在DefaultStateMachineService类中,在获取SM期间,服务会创建一个新的SM,并且JpaPersistingStateMachineInterceptor会将新SM保持为初始状态,然后DefaultStateMachineService从DB读取状态(该状态已被覆盖)并调用restoreStateMachine方法处于覆盖状态。因此,要解决此问题,您必须创建自己的StateMachineService实现。


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.Lifecycle;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.StateMachineContext;
import org.springframework.statemachine.StateMachineException;
import org.springframework.statemachine.StateMachinePersist;
import org.springframework.statemachine.access.StateMachineAccess;
import org.springframework.statemachine.access.StateMachineFunction;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.service.DefaultStateMachineService;
import org.springframework.statemachine.service.StateMachineService;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;

public class PrimeStateMachineService<S,E> implements StateMachineService<S,E>,DisposableBean {

    private final static Log log = LogFactory.getLog(DefaultStateMachineService.class);
    private final StateMachineFactory<S,E> stateMachineFactory;
    private final Map<String,StateMachine<S,E>> machines = new HashMap<String,E>>();
    private StateMachinePersist<S,E,String> stateMachinePersist;

    /**
     * Instantiates a new default state machine service.
     *
     * @param stateMachineFactory the state machine factory
     */
    public PrimeStateMachineService(StateMachineFactory<S,E> stateMachineFactory) {
        this(stateMachineFactory,null);
    }

    /**
     * Instantiates a new default state machine service.
     *
     * @param stateMachineFactory the state machine factory
     * @param stateMachinePersist the state machine persist
     */
    public PrimeStateMachineService(StateMachineFactory<S,E> stateMachineFactory,StateMachinePersist<S,String> stateMachinePersist) {
        Assert.notNull(stateMachineFactory,"'stateMachineFactory' must be set");
        this.stateMachineFactory = stateMachineFactory;
        this.stateMachinePersist = stateMachinePersist;
    }

    @Override
    public final void destroy() throws Exception {
        doStop();
    }

    @Override
    public StateMachine<S,E> acquireStateMachine(String machineId) {
        return acquireStateMachine(machineId,true);
    }

    @Override
    public StateMachine<S,E> acquireStateMachine(String machineId,boolean start) {
        log.info("Acquiring machine with id " + machineId);
        StateMachine<S,E> stateMachine;
        synchronized (machines) {
            stateMachine = machines.get(machineId);
            if (isNull(stateMachine)) {
                if (nonNull(stateMachinePersist)) {
                    try {
                        StateMachineContext<S,E> stateMachineContext = stateMachinePersist.read(machineId);
                        if (isNull(stateMachineContext)) {
                            stateMachine = stateMachineFactory.getStateMachine(machineId);
                            log.info("Getting new machine from factory with id " + machineId);
                        } else {
                            stateMachine = restoreStateMachine(stateMachineFactory.getStateMachine(machineId),stateMachineContext);
                            log.info("State machine restored from repository with id " + machineId);
                        }
                    } catch (Exception e) {
                        log.error("Error handling context",e);
                        throw new StateMachineException("Unable to read context from store",e);
                    }
                }
                machines.put(machineId,stateMachine);
            }
        }
        return handleStart(stateMachine,start);
    }

    @Override
    public void releaseStateMachine(String machineId) {
        log.info("Releasing machine with id " + machineId);
        synchronized (machines) {
            StateMachine<S,E> stateMachine = machines.remove(machineId);
            if (stateMachine != null) {
                log.info("Found machine with id " + machineId);
                stateMachine.stop();
            }
        }
    }

    @Override
    public void releaseStateMachine(String machineId,boolean stop) {
        log.info("Releasing machine with id " + machineId);
        synchronized (machines) {
            StateMachine<S,E> stateMachine = machines.remove(machineId);
            if (stateMachine != null) {
                log.info("Found machine with id " + machineId);
                handleStop(stateMachine,stop);
            }
        }
    }

    /**
     * Determines if the given machine identifier denotes a known managed state machine.
     *
     * @param machineId machine identifier
     * @return true if machineId denotes a known managed state machine currently in memory
     */
    public boolean hasStateMachine(String machineId) {
        synchronized (machines) {
            return machines.containsKey(machineId);
        }
    }

    /**
     * Sets the state machine persist.
     *
     * @param stateMachinePersist the state machine persist
     */
    public void setStateMachinePersist(StateMachinePersist<S,String> stateMachinePersist) {
        this.stateMachinePersist = stateMachinePersist;
    }

    protected void doStop() {
        log.info("Entering stop sequence,stopping all managed machines");
        synchronized (machines) {
            ArrayList<String> machineIds = new ArrayList<>(machines.keySet());
            for (String machineId : machineIds) {
                releaseStateMachine(machineId,true);
            }
        }
    }

    protected StateMachine<S,E> restoreStateMachine(StateMachine<S,E> stateMachine,final StateMachineContext<S,E> stateMachineContext) {
        if (stateMachineContext == null) {
            return stateMachine;
        }

        stateMachine.stop();

        stateMachine
                .getStateMachineAccessor()
                .doWithAllRegions(function -> function.resetStateMachine(stateMachineContext));

        return stateMachine;
    }

    protected StateMachine<S,E> handleStart(StateMachine<S,boolean start) {
        if (start) {
            if (!((Lifecycle) stateMachine).isRunning()) {
                PrimeStateMachineService.StartListener<S,E> listener = new PrimeStateMachineService.StartListener<>(stateMachine);
                stateMachine.addStateListener(listener);
                stateMachine.start();
                try {
                    listener.latch.await();
                } catch (InterruptedException e) {
                }
            }
        }
        return stateMachine;
    }

    protected StateMachine<S,E> handleStop(StateMachine<S,boolean stop) {
        if (stop) {
            if (((Lifecycle) stateMachine).isRunning()) {
                PrimeStateMachineService.StopListener<S,E> listener = new PrimeStateMachineService.StopListener<>(stateMachine);
                stateMachine.addStateListener(listener);
                stateMachine.stop();
                try {
                    listener.latch.await();
                } catch (InterruptedException e) {
                }
            }
        }
        return stateMachine;
    }

    private static class StartListener<S,E> extends StateMachineListenerAdapter<S,E> {

        final CountDownLatch latch = new CountDownLatch(1);
        final StateMachine<S,E> stateMachine;

        public StartListener(StateMachine<S,E> stateMachine) {
            this.stateMachine = stateMachine;
        }

        @Override
        public void stateMachineStarted(StateMachine<S,E> stateMachine) {
            this.stateMachine.removeStateListener(this);
            latch.countDown();
        }
    }

    private static class StopListener<S,E> stateMachine;

        public StopListener(StateMachine<S,E> stateMachine) {
            this.stateMachine = stateMachine;
        }

        @Override
        public void stateMachineStopped(StateMachine<S,E> stateMachine) {
            this.stateMachine.removeStateListener(this);
            latch.countDown();
        }
    }
}
,

我在功能测试上下文中遇到了同样的问题。关键是通过服务(不释放它)在内存中创建和播种所需的状态机,并端到端地运行测试。这样服务就没有提交持久化,导致状态回滚到初始状态

public static StateMachine restoreMachine(final StateMachine<States,Events> stateMachine,final States currentState,final ExtendedState extendedState) {
        stateMachine.getStateMachineAccessor().doWithAllRegions(t ->
                t.resetStateMachine(
                        new DefaultStateMachineContext<>(currentState,Events.ANY_DESIRED_STATE,null,extendedState,"your-machine-id")));
        return stateMachine;
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?