Как обрабатывать события, которые не были обработаны конечным автоматом
Допустим, у нас есть следующая конфигурация конечного автомата:
transitions.withExternal()
.source(FIRST)
.target(SECOND)
.event(STEP_EVENT)
.and()
.source(SECOND)
.target(EXIT)
.event(EXIT_EVENT)
Список событий: STEP_EVENT, EXIT_EVENT, UNUSED_EVENT
stateMachine.init();
// FIRST state
stateMachine.sendEvent(STEP_EVENT);
/* state moves to SECOND
because there is a transition with current state as a source
and STEP_EVENT as transition event */
stateMachine.sendEvent(UNUSED_EVENT);
/* no state change.
This will trigger "eventNotAccepted(Message<Events> event)"
in state machine listener,
because UNUSED_EVENT is never mentioned in SM config */
stateMachine.sendEvent(STEP_EVENT);
/* nothing will happen!!!
No state change, as there is no transition
which has current state (SECOND) as source
and STEP_EVENT as transition event,
and no eventNotAccepted call.
But I need it, I want to fail here! */
stateMachine.sendEvent(EXIT_EVENT);
// state will move to EXIT
Проблема в том, что когда я отправляю событие, которое является частью конфигурации, но не применимо для текущего состояния, ничего не происходит.
Я не знаю, изменилось ли состояние из-за охраны или из-за отсутствия перехода с текущим состоянием и моим событием.
Есть ли способ справиться с такими случаями?
2 ответа
Для регистрации событий, которые не применимы для вашего текущего состояния, вы можете использовать слушатель StateMachine. Существует метод, вызываемый каждый раз, когда в конечном автомате передается событие, которое не удовлетворяет определенным переходам и событиям.
В Конфигурации конечного автомата вам необходимо переопределить:
public void configure(StateMachineConfigurationConfigurer<State, Event> config) {
config.withConfiguration()
.listener(customListener());
}
и реализовать свой собственный слушатель - самый простой способ это использовать StateMachineListenerAdapter
и переопределить eventNotAccepted(Message event)
метод:
private StateMachineListenerAdapter<State, Event> customListener() {
return new StateMachineEventListenerAdapter<State, Event>() {
@Override
public void eventNotAccepted(Message event) {
//LOG which event was not accepted etc.
}
}
}
Для регистрации результатов охраны - используйте сообщения журнала в самих охранниках.
Если вы хотите раскрыть причину вне защиты, вы можете создать пару ключ-значение и использовать расширенный контекст StateMachine для записи имени охранника и причины, по которой и событие было отклонено. Контекст может использоваться для создания пользовательского исключения или передачи кода вызывающей стороны о том, что произошло.
Решено! Как это часто бывает, решение было слишком простым для меня, чтобы наблюдать его:(. Поэтому метод, который отправляет событие в SM, имеет логический параметр возврата. И если событие было обработано и обработано, он возвращает true и false в противном случае.
Вот и все - просто проверьте возвращаемое значение!