/* * 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.test.support; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import org.springframework.messaging.Message; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.listener.StateMachineListener; import org.springframework.statemachine.listener.StateMachineListenerAdapter; import org.springframework.statemachine.state.State; import org.springframework.statemachine.transition.Transition; /** * A {@link StateMachineListener} which is used during the tests * to assert correct count of listener callbacks. * * @author Janne Valkealahti * * @param <S> the type of state * @param <E> the type of event */ public class LatchStateMachineListener<S, E> extends StateMachineListenerAdapter<S, E> { private final Object lock = new Object(); private volatile CountDownLatch stateChangedLatch = new CountDownLatch(1); private volatile CountDownLatch stateEnteredLatch = new CountDownLatch(1); private volatile CountDownLatch stateExitedLatch = new CountDownLatch(1); private volatile CountDownLatch eventNotAcceptedLatch = new CountDownLatch(1); private volatile CountDownLatch transitionLatch = new CountDownLatch(1); private volatile CountDownLatch transitionStartedLatch = new CountDownLatch(1); private volatile CountDownLatch transitionEndedLatch = new CountDownLatch(1); private volatile CountDownLatch stateMachineStartedLatch = new CountDownLatch(1); private volatile CountDownLatch stateMachineStoppedLatch = new CountDownLatch(1); private volatile CountDownLatch extendedStateChangedLatch = new CountDownLatch(1); private final List<StateChangedWrapper<S, E>> stateChanged = new ArrayList<StateChangedWrapper<S, E>>(); private final List<State<S, E>> stateEntered = new ArrayList<State<S, E>>(); private final List<State<S, E>> stateExited = new ArrayList<State<S, E>>(); private final List<Message<E>> eventNotAccepted = new ArrayList<Message<E>>(); private final List<Transition<S, E>> transition = new ArrayList<Transition<S, E>>(); private final List<Transition<S, E>> transitionStarted = new ArrayList<Transition<S, E>>(); private final List<Transition<S, E>> transitionEnded = new ArrayList<Transition<S, E>>(); private final List<StateMachine<S, E>> stateMachineStarted = new ArrayList<StateMachine<S, E>>(); private final List<StateMachine<S, E>> stateMachineStopped = new ArrayList<StateMachine<S, E>>(); private final List<ExtendedStateChangedWrapper> extendedStateChanged = new ArrayList<ExtendedStateChangedWrapper>(); @Override public void stateChanged(State<S, E> from, State<S, E> to) { synchronized (lock) { this.stateChanged.add(new StateChangedWrapper<>(from, to)); this.stateChangedLatch.countDown(); } } @Override public void stateEntered(State<S, E> state) { synchronized (lock) { this.stateEntered.add(state); this.stateEnteredLatch.countDown(); } } @Override public void stateExited(State<S, E> state) { synchronized (lock) { this.stateExited.add(state); this.stateExitedLatch.countDown(); } } @Override public void eventNotAccepted(Message<E> event) { synchronized (lock) { this.eventNotAccepted.add(event); this.eventNotAcceptedLatch.countDown(); } } @Override public void transition(Transition<S, E> transition) { synchronized (lock) { this.transition.add(transition); this.transitionLatch.countDown(); } } @Override public void transitionStarted(Transition<S, E> transition) { synchronized (lock) { this.transitionStarted.add(transition); this.transitionStartedLatch.countDown(); } } @Override public void transitionEnded(Transition<S, E> transition) { synchronized (lock) { this.transitionEnded.add(transition); this.transitionEndedLatch.countDown(); } } @Override public void stateMachineStarted(StateMachine<S, E> stateMachine) { synchronized (lock) { this.stateMachineStarted.add(stateMachine); this.stateMachineStartedLatch.countDown(); } } @Override public void stateMachineStopped(StateMachine<S, E> stateMachine) { synchronized (lock) { this.stateMachineStopped.add(stateMachine); this.stateMachineStoppedLatch.countDown(); } } @Override public void extendedStateChanged(Object key, Object value) { synchronized (lock) { this.extendedStateChanged.add(new ExtendedStateChangedWrapper(key, value)); this.extendedStateChangedLatch.countDown(); } } public void reset(int stateChangedCount, int stateEnteredCount, int stateExitedCount, int eventNotAcceptedCount, int transitionCount, int transitionStartedCount, int transitionEndedCount, int stateMachineStartedCount, int stateMachineStoppedCount, int extendedStateChangedCount) { synchronized (lock) { this.stateChangedLatch = new CountDownLatch(stateChangedCount); this.stateEnteredLatch = new CountDownLatch(stateEnteredCount); this.stateExitedLatch = new CountDownLatch(stateExitedCount); this.eventNotAcceptedLatch = new CountDownLatch(eventNotAcceptedCount); this.transitionLatch = new CountDownLatch(transitionCount); this.transitionStartedLatch = new CountDownLatch(transitionStartedCount); this.transitionEndedLatch = new CountDownLatch(transitionEndedCount); this.stateMachineStartedLatch = new CountDownLatch(stateMachineStartedCount); this.stateMachineStoppedLatch = new CountDownLatch(stateMachineStoppedCount); this.extendedStateChangedLatch = new CountDownLatch(extendedStateChangedCount); this.stateChanged.clear(); this.stateEntered.clear(); this.stateExited.clear(); this.eventNotAccepted.clear(); this.transition.clear(); this.transitionStarted.clear(); this.transitionEnded.clear(); this.stateMachineStarted.clear(); this.stateMachineStopped.clear(); this.extendedStateChanged.clear(); } } public CountDownLatch getStateChangedLatch() { return stateChangedLatch; } public CountDownLatch getStateEnteredLatch() { return stateEnteredLatch; } public CountDownLatch getStateExitedLatch() { return stateExitedLatch; } public CountDownLatch getEventNotAcceptedLatch() { return eventNotAcceptedLatch; } public CountDownLatch getTransitionLatch() { return transitionLatch; } public CountDownLatch getTransitionStartedLatch() { return transitionStartedLatch; } public CountDownLatch getTransitionEndedLatch() { return transitionEndedLatch; } public CountDownLatch getStateMachineStartedLatch() { return stateMachineStartedLatch; } public CountDownLatch getStateMachineStoppedLatch() { return stateMachineStoppedLatch; } public CountDownLatch getExtendedStateChangedLatch() { return extendedStateChangedLatch; } public List<StateChangedWrapper<S, E>> getStateChanged() { return stateChanged; } public List<State<S, E>> getStateEntered() { return stateEntered; } public List<State<S, E>> getStateExited() { return stateExited; } public List<Message<E>> getEventNotAccepted() { return eventNotAccepted; } public List<Transition<S, E>> getTransition() { return transition; } public List<Transition<S, E>> getTransitionStarted() { return transitionStarted; } public List<Transition<S, E>> getTransitionEnded() { return transitionEnded; } public List<StateMachine<S, E>> getStateMachineStarted() { return stateMachineStarted; } public List<StateMachine<S, E>> getStateMachineStopped() { return stateMachineStopped; } public List<ExtendedStateChangedWrapper> getExtendedStateChanged() { return extendedStateChanged; } public static class StateChangedWrapper<S, E> { final State<S, E> from; final State<S, E> to; public StateChangedWrapper(State<S, E> from, State<S, E> to) { this.from = from; this.to = to; } } public static class ExtendedStateChangedWrapper { final Object key; final Object value; public ExtendedStateChangedWrapper(Object key, Object value) { this.key = key; this.value = value; } } }