/*
* 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;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Before;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.statemachine.action.Action;
import org.springframework.statemachine.guard.Guard;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;
/**
* Base class for stace machine tests.
*
* @author Janne Valkealahti
*
*/
public abstract class AbstractStateMachineTests {
private final static Log log = LogFactory.getLog(AbstractStateMachineTests.class);
protected AnnotationConfigApplicationContext context;
@Before
public void setup() {
context = buildContext();
}
@After
public void clean() {
if (context != null) {
context.close();
}
}
protected AnnotationConfigApplicationContext buildContext() {
return null;
}
public enum TestStates {
SI,S1,S2,S3,S4,SF,SH,
S10,S11,S101,S111,S112,S12,S121,S122,S13,
S20,S21,S201,S211,S212,
S1011,S1012,S2011,S2012,
S30,S31,S32,S33
}
public enum TestEvents {
E1,E2,E3,E4,EF,EH
}
public static enum TestStates2 {
BUSY, PLAYING, PAUSED,
IDLE, CLOSED, OPEN,
PAUSED1, PAUSED2
}
public static enum TestStates3 {
READY,
FORK, JOIN,
TASKS, T1, T1E, T2, T2E, T3, T3E
}
public static enum TestEvents2 {
PLAY, STOP, PAUSE, EJECT, LOAD
}
@Configuration
public static class BaseConfig {
@Bean(name = StateMachineSystemConstants.TASK_EXECUTOR_BEAN_NAME)
public TaskExecutor taskExecutor() {
return new SyncTaskExecutor();
}
@Bean
public TaskScheduler taskScheduler() {
return new ConcurrentTaskScheduler();
}
}
@Configuration
public static class BaseConfig2 {
@Bean(name = StateMachineSystemConstants.TASK_EXECUTOR_BEAN_NAME)
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
return taskExecutor;
}
@Bean
public TaskScheduler taskScheduler() {
return new ConcurrentTaskScheduler();
}
}
public static class TestEntryAction extends AbstractTestAction {
public TestEntryAction() {
super();
}
public TestEntryAction(String message) {
super(message);
}
@Override
public String toString() {
return "TestEntryAction [message=" + message + "]";
}
}
public static class TestExitAction extends AbstractTestAction {
public TestExitAction() {
super();
}
public TestExitAction(String message) {
super(message);
}
@Override
public String toString() {
return "TestExitAction [message=" + message + "]";
}
}
public static class TestAction extends AbstractTestAction {
}
public static class TestSleepAction extends AbstractTestAction {
long sleep;
long now;
public CountDownLatch onExecuteStartLatch = new CountDownLatch(1);
public AtomicBoolean interrupted = new AtomicBoolean(false);
public CountDownLatch interruptedLatch = new CountDownLatch(1);
public TestSleepAction(long sleep) {
super();
this.sleep = sleep;
}
@Override
public void execute(StateContext<TestStates, TestEvents> context) {
onExecuteStartLatch.countDown();
now = System.currentTimeMillis();
if (sleep > 0) {
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
interrupted.set(true);
interruptedLatch.countDown();
}
}
super.execute(context);
}
}
public static class TestGuard implements Guard<TestStates, TestEvents> {
public CountDownLatch onEvaluateLatch = new CountDownLatch(1);
boolean evaluationResult = true;
public TestGuard() {
}
public TestGuard(boolean evaluationResult) {
this.evaluationResult = evaluationResult;
}
@Override
public boolean evaluate(StateContext<TestStates, TestEvents> context) {
onEvaluateLatch.countDown();
return evaluationResult;
}
}
protected static class AbstractTestAction implements Action<TestStates, TestEvents> {
protected String message = null;
public CountDownLatch onExecuteLatch = new CountDownLatch(1);
public List<StateContext<TestStates, TestEvents>> stateContexts = new ArrayList<StateContext<TestStates, TestEvents>>();
public AbstractTestAction() {
}
public AbstractTestAction(String message) {
this.message = message;
}
@Override
public void execute(StateContext<TestStates, TestEvents> context) {
if (message != null) {
log.info(this);
}
stateContexts.add(context);
onExecuteLatch.countDown();
}
}
public static class TestStateMachineListener extends StateMachineListenerAdapter<TestStates, TestEvents> {
public volatile CountDownLatch stateChangedLatch = new CountDownLatch(0);
public volatile CountDownLatch stateMachineStartedLatch = new CountDownLatch(3);
@Override
public void stateChanged(State<TestStates, TestEvents> from, State<TestStates, TestEvents> to) {
stateChangedLatch.countDown();
}
@Override
public void stateMachineStarted(StateMachine<TestStates, TestEvents> stateMachine) {
stateMachineStartedLatch.countDown();
}
public void reset(int c1, int c2) {
stateChangedLatch = new CountDownLatch(c1);
stateMachineStartedLatch = new CountDownLatch(c2);
}
}
}