From 90051f398949547393d110ef046a39d79523bcdd Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sat, 21 Mar 2015 10:33:34 +0000 Subject: [PATCH] Add more state events - Now app context and listener are notified when state is exited or entered. --- .../DefaultStateMachineEventPublisher.java | 14 +++++ .../event/OnStateChangedEvent.java | 2 +- .../statemachine/event/OnStateEntryEvent.java | 56 +++++++++++++++++++ .../statemachine/event/OnStateExitEvent.java | 56 +++++++++++++++++++ .../event/StateMachineEventPublisher.java | 16 ++++++ .../CompositeStateMachineListener.java | 16 ++++++ .../listener/StateMachineListener.java | 14 +++++ .../support/AbstractStateMachine.java | 18 ++++++ .../statemachine/listener/ListenerTests.java | 8 +++ 9 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateEntryEvent.java create mode 100644 spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateExitEvent.java diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/DefaultStateMachineEventPublisher.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/DefaultStateMachineEventPublisher.java index 81220d06..cf744869 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/DefaultStateMachineEventPublisher.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/DefaultStateMachineEventPublisher.java @@ -57,6 +57,20 @@ public class DefaultStateMachineEventPublisher implements StateMachineEventPubli } } + @Override + public void publishStateEntered(Object source, State state) { + if (applicationEventPublisher != null) { + applicationEventPublisher.publishEvent(new OnStateEntryEvent(source, state)); + } + } + + @Override + public void publishStateExited(Object source, State state) { + if (applicationEventPublisher != null) { + applicationEventPublisher.publishEvent(new OnStateExitEvent(source, state)); + } + } + @Override public void publishTransitionStart(Object source, Transition transition) { if (applicationEventPublisher != null) { diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateChangedEvent.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateChangedEvent.java index 9eccdaa7..65ce86be 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateChangedEvent.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateChangedEvent.java @@ -30,7 +30,7 @@ public class OnStateChangedEvent extends StateMachineEvent { private final State targetState; /** - * Instantiates a new granted event. + * Instantiates a new on state changed event. * * @param source the component that published the event (never {@code null}) */ diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateEntryEvent.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateEntryEvent.java new file mode 100644 index 00000000..42daf7c9 --- /dev/null +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateEntryEvent.java @@ -0,0 +1,56 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.statemachine.event; + +import org.springframework.statemachine.state.State; + +/** + * Generic event representing that state has been entered. + * + * @author Janne Valkealahti + * + */ +@SuppressWarnings("serial") +public class OnStateEntryEvent extends StateMachineEvent { + + private final State state; + + /** + * Instantiates a new on state entry event. + * + * @param source the source + * @param state the state + */ + public OnStateEntryEvent(Object source, State state) { + super(source); + this.state = state; + } + + /** + * Gets the state. + * + * @return the state + */ + public State getState() { + return state; + } + + @Override + public String toString() { + return "OnStateEntryEvent [state=" + state + "]"; + } + +} diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateExitEvent.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateExitEvent.java new file mode 100644 index 00000000..b154db38 --- /dev/null +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/OnStateExitEvent.java @@ -0,0 +1,56 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.statemachine.event; + +import org.springframework.statemachine.state.State; + +/** + * Generic event representing that state has been exited. + * + * @author Janne Valkealahti + * + */ +@SuppressWarnings("serial") +public class OnStateExitEvent extends StateMachineEvent { + + private final State state; + + /** + * Instantiates a new on state exit event. + * + * @param source the source + * @param state the state + */ + public OnStateExitEvent(Object source, State state) { + super(source); + this.state = state; + } + + /** + * Gets the state. + * + * @return the state + */ + public State getState() { + return state; + } + + @Override + public String toString() { + return "OnStateExitEvent [state=" + state + "]"; + } + +} diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/StateMachineEventPublisher.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/StateMachineEventPublisher.java index 9f935033..b2f76ef7 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/StateMachineEventPublisher.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/event/StateMachineEventPublisher.java @@ -35,6 +35,22 @@ public interface StateMachineEventPublisher { */ void publishStateChanged(Object source, State sourceState, State targetState); + /** + * Publish a state entered event. + * + * @param source the source + * @param state the state + */ + void publishStateEntered(Object source, State state); + + /** + * Publish a state exited event. + * + * @param source the source + * @param state the state + */ + void publishStateExited(Object source, State state); + /** * Publish a transition start event. * diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/CompositeStateMachineListener.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/CompositeStateMachineListener.java index 9906ff7b..be85e23c 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/CompositeStateMachineListener.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/CompositeStateMachineListener.java @@ -39,6 +39,22 @@ public class CompositeStateMachineListener extends AbstractCompositeListene } } + @Override + public void stateEntered(State state) { + for (Iterator> iterator = getListeners().reverse(); iterator.hasNext();) { + StateMachineListener listener = iterator.next(); + listener.stateEntered(state); + } + } + + @Override + public void stateExited(State state) { + for (Iterator> iterator = getListeners().reverse(); iterator.hasNext();) { + StateMachineListener listener = iterator.next(); + listener.stateExited(state); + } + } + @Override public void transition(Transition transition) { for (Iterator> iterator = getListeners().reverse(); iterator.hasNext();) { diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListener.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListener.java index a0e97acb..f1c940a7 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListener.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/listener/StateMachineListener.java @@ -36,6 +36,20 @@ public interface StateMachineListener { */ void stateChanged(State from, State to); + /** + * Notified when state is entered. + * + * @param state the state + */ + void stateEntered(State state); + + /** + * Notified when state is exited. + * + * @param state the state + */ + void stateExited(State state); + /** * Notified when transition happened. * diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java index bfb1b1de..71be7db1 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java @@ -316,6 +316,7 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport new HashMap()); StateContext stateContext = new DefaultStateContext(messageHeaders, extendedState, transition, this); state.exit(event != null ? event.getPayload() : null, stateContext); + notifyStateExited(state); } } @@ -326,6 +327,7 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport new HashMap()); StateContext stateContext = new DefaultStateContext(messageHeaders, extendedState, transition, this); state.entry(event != null ? event.getPayload() : null, stateContext); + notifyStateEntered(state); } } @@ -544,6 +546,22 @@ public abstract class AbstractStateMachine extends LifecycleObjectSupport } } + private void notifyStateEntered(State state) { + stateListener.stateEntered(state); + StateMachineEventPublisher eventPublisher = getStateMachineEventPublisher(); + if (eventPublisher != null) { + eventPublisher.publishStateEntered(this, state); + } + } + + private void notifyStateExited(State state) { + stateListener.stateExited(state); + StateMachineEventPublisher eventPublisher = getStateMachineEventPublisher(); + if (eventPublisher != null) { + eventPublisher.publishStateExited(this, state); + } + } + private void notifyTransitionStart(Transition transition) { stateListener.transitionStarted(transition); StateMachineEventPublisher eventPublisher = getStateMachineEventPublisher(); diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/listener/ListenerTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/listener/ListenerTests.java index c039aba1..04fcfb1b 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/listener/ListenerTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/listener/ListenerTests.java @@ -105,6 +105,14 @@ public class ListenerTests extends AbstractStateMachineTests { states.add(new Holder(from, to)); } + @Override + public void stateEntered(State state) { + } + + @Override + public void stateExited(State state) { + } + static class Holder { State from; State to;