/*
* 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.annotation;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertThat;
import java.util.EnumSet;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.AbstractStateMachineTests;
import org.springframework.statemachine.ExtendedState;
import org.springframework.statemachine.ObjectStateMachine;
import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.StateMachineSystemConstants;
import org.springframework.statemachine.action.Action;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.config.configurers.StateConfigurer.History;
public class MethodAnnotationTests extends AbstractStateMachineTests {
@Override
protected AnnotationConfigApplicationContext buildContext() {
return new AnnotationConfigApplicationContext();
}
@Test
@SuppressWarnings("unchecked")
public void testOnTransition() throws Exception {
context.register(BaseConfig.class, BeanConfig1.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
assertThat(context.containsBean("fooMachine"), is(true));
Bean1 bean1 = context.getBean(Bean1.class);
bean1.reset(1, 1, 1, 1, 1, 1, 1, 1);
machine.start();
assertThat(bean1.onTransitionFromS1ToS2Latch.await(1, TimeUnit.SECONDS), is(false));
assertThat(bean1.onTransitionLatch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean1.onTransitionFromS1ToS2Count, is(0));
assertThat(bean1.onTransitionCount, is(1));
bean1.reset(1, 1, 1, 1, 1, 1, 1, 1);
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
assertThat(bean1.onTransitionFromS1ToS2Latch.await(1, TimeUnit.SECONDS), is(true));
assertThat(bean1.onTransitionLatch.await(1, TimeUnit.SECONDS), is(true));
assertThat(bean1.onTransitionFromS1ToS2Count, is(1));
assertThat(bean1.onTransitionCount, is(1));
}
@Test
@SuppressWarnings("unchecked")
public void testOnStateChanged() throws Exception {
context.register(BaseConfig.class, BeanConfig1.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
assertThat(context.containsBean("fooMachine"), is(true));
Bean1 bean1 = context.getBean(Bean1.class);
bean1.reset(1, 1, 1, 1, 1, 1, 1, 1);
machine.start();
assertThat(bean1.onStateChangedFromS1ToS2Latch.await(1, TimeUnit.SECONDS), is(false));
assertThat(bean1.onStateChangedLatch.await(1, TimeUnit.SECONDS), is(true));
assertThat(bean1.onStateChangedFromS1ToS2Count, is(0));
assertThat(bean1.onStateChangedCount, is(1));
bean1.reset(1, 1, 1, 1, 1, 1, 1, 1);
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
assertThat(bean1.onStateChangedFromS1ToS2Latch.await(1, TimeUnit.SECONDS), is(true));
assertThat(bean1.onStateChangedLatch.await(1, TimeUnit.SECONDS), is(true));
assertThat(bean1.onStateChangedFromS1ToS2Count, is(1));
assertThat(bean1.onStateChangedCount, is(1));
}
@Test
@SuppressWarnings("unchecked")
public void testOnStateMachineStartStop() throws Exception {
context.register(BaseConfig.class, BeanConfig1.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
assertThat(context.containsBean("fooMachine"), is(true));
Bean1 bean1 = context.getBean(Bean1.class);
bean1.reset(1, 1, 1, 1, 1, 1, 1, 1);
machine.start();
assertThat(bean1.onStateMachineStartLatch.await(1, TimeUnit.SECONDS), is(true));
assertThat(bean1.onStateMachineStartCount, is(1));
assertThat(bean1.onStateMachineStopLatch.await(1, TimeUnit.SECONDS), is(false));
assertThat(bean1.onStateMachineStopCount, is(0));
bean1.reset(1, 1, 1, 1, 1, 1, 1, 1);
machine.stop();
assertThat(bean1.onStateMachineStartLatch.await(1, TimeUnit.SECONDS), is(false));
assertThat(bean1.onStateMachineStartCount, is(0));
assertThat(bean1.onStateMachineStopLatch.await(1, TimeUnit.SECONDS), is(true));
assertThat(bean1.onStateMachineStopCount, is(1));
}
@Test
@SuppressWarnings("unchecked")
public void testOnExtendedStateChanged() throws Exception {
context.register(BaseConfig.class, BeanConfig5.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
assertThat(context.containsBean("fooMachine"), is(true));
Bean5 bean5 = context.getBean(Bean5.class);
machine.start();
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).setHeader("V1", "V1val").build());
assertThat(bean5.onExtendedStateChanged1Latch.await(1, TimeUnit.SECONDS), is(true));
assertThat(bean5.onExtendedStateChanged1Count, is(1));
assertThat(bean5.onExtendedStateChanged2Latch.await(1, TimeUnit.SECONDS), is(true));
assertThat(bean5.onExtendedStateChanged2Count, is(1));
assertThat(bean5.onExtendedStateChanged2Value, is("V1val"));
assertThat(bean5.onExtendedStateChangedKeyV2Latch.await(1, TimeUnit.SECONDS), is(false));
assertThat(bean5.onExtendedStateChangedKeyV2Count, is(0));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodAnnotations2() throws Exception {
context.register(BaseConfig.class, BeanConfig2.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
assertThat(context.containsBean("fooMachine"), is(true));
machine.start();
Bean2 bean2 = context.getBean(Bean2.class);
// this event should cause 'method1' to get called
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).setHeader("foo", "jee").build());
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E2).build());
assertThat(bean2.onMethod1Latch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean2.headers, notNullValue());
assertThat((String)bean2.headers.get("foo"), is("jee"));
assertThat(bean2.extendedState, notNullValue());
assertThat(bean2.onMethod2Latch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean2.variable, notNullValue());
assertThat((String)bean2.variable, is("jee"));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodAnnotations3() throws Exception {
context.register(BaseConfig.class, BeanConfig3.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
assertThat(context.containsBean("fooMachine"), is(true));
machine.start();
Bean3 bean3 = context.getBean(Bean3.class);
// this event should cause 'method1' to get called
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
assertThat(bean3.onStateChangedLatch.await(2, TimeUnit.SECONDS), is(true));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodAnnotations4() throws Exception {
context.register(BaseConfig.class, BeanConfig4.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
assertThat(context.containsBean("fooMachine"), is(true));
Bean4 bean4 = context.getBean(Bean4.class);
machine.start();
assertThat(bean4.onStateEntryLatch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean4.onStateExitLatch.await(2, TimeUnit.SECONDS), is(false));
assertThat(bean4.onStateEntryCount, is(1));
assertThat(bean4.onStateExitCount, is(0));
bean4.reset(1, 1);
// this event should cause 'method1' to get called
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build());
assertThat(bean4.onStateEntryLatch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean4.onStateExitLatch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean4.onStateEntryCount, is(1));
assertThat(bean4.onStateExitCount, is(1));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodAnnotations5() throws Exception {
context.register(BaseConfig.class, BeanConfig6.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
Bean6 bean6 = context.getBean(Bean6.class);
machine.start();
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E4).build());
assertThat(bean6.onEventNotAccepted1Latch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean6.onEventNotAccepted2Latch.await(2, TimeUnit.SECONDS), is(false));
assertThat(bean6.onEventNotAccepted3Latch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean6.onEventNotAccepted4Latch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean6.onEventNotAccepted4Message, notNullValue());
assertThat(bean6.onEventNotAccepted4Message.getPayload(), is(TestEvents.E4));
assertThat(bean6.onEventNotAccepted5Latch.await(2, TimeUnit.SECONDS), is(true));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodAnnotations6() throws Exception {
context.register(BaseConfig.class, BeanConfig7.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
Bean7 bean7 = context.getBean(Bean7.class);
machine.start();
machine.sendEvent(MessageBuilder.withPayload(TestEvents.E4).build());
machine.setStateMachineError(new RuntimeException());
assertThat(bean7.OnStateMachineError1Latch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean7.OnStateMachineError2Latch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean7.OnStateMachineError2Exception, notNullValue());
}
@Test
@SuppressWarnings("unchecked")
public void testMethodAnnotations7() throws Exception {
context.register(BaseConfig.class, BeanConfig8.class, Config1.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
Bean8 bean8 = context.getBean(Bean8.class);
machine.start();
machine.sendEvent(MessageBuilder.withPayload(TestEvents.EF).build());
assertThat(bean8.OnTransition1Latch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean8.OnTransition2Latch.await(2, TimeUnit.SECONDS), is(true));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodAnnotations8() throws Exception {
context.register(BaseConfig.class, BeanConfig9.class, Config2.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
Bean9 bean9 = context.getBean(Bean9.class);
machine.start();
machine.sendEvent(TestEvents.E1);
machine.sendEvent(TestEvents.E2);
machine.sendEvent(TestEvents.E3);
machine.sendEvent(TestEvents.E4);
assertThat(machine.getState().getIds(), contains(TestStates.S2, TestStates.S21));
assertThat(bean9.OnStateEntry1Latch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean9.OnTransition1Latch.await(2, TimeUnit.SECONDS), is(true));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodAnnotations9() throws Exception {
context.register(BaseConfig.class, BeanConfig10.class, Config3.class);
context.refresh();
ObjectStateMachine<TestStates,TestEvents> machine =
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class);
Bean10 bean10 = context.getBean(Bean10.class);
machine.start();
machine.sendEvent(TestEvents.E1);
machine.sendEvent(TestEvents.E2);
machine.sendEvent(TestEvents.E3);
machine.sendEvent(TestEvents.E4);
assertThat(machine.getState().getIds(), contains(TestStates.S2, TestStates.S21));
assertThat(bean10.OnStateEntry1Latch.await(2, TimeUnit.SECONDS), is(true));
assertThat(bean10.OnTransition1Latch.await(2, TimeUnit.SECONDS), is(true));
}
@WithStateMachine
static class Bean1 {
CountDownLatch onTransitionFromS1ToS2Latch = new CountDownLatch(1);
CountDownLatch onTransitionLatch = new CountDownLatch(1);
CountDownLatch onStateChangedFromS1ToS2Latch = new CountDownLatch(1);
CountDownLatch onStateChangedLatch = new CountDownLatch(1);
CountDownLatch onTransitionEndLatch = new CountDownLatch(1);
CountDownLatch onTransitionStartLatch = new CountDownLatch(1);
CountDownLatch onStateMachineStartLatch = new CountDownLatch(1);
CountDownLatch onStateMachineStopLatch = new CountDownLatch(1);
int onTransitionFromS1ToS2Count = 0;
int onTransitionCount = 0;
int onStateChangedFromS1ToS2Count = 0;
int onStateChangedCount = 0;
int onTransitionEndCount = 0;
int onTransitionStartCount = 0;
int onStateMachineStartCount = 0;
int onStateMachineStopCount = 0;
@OnTransition(source = "S1", target = "S2")
public void onTransitionFromS1ToS2() {
onTransitionFromS1ToS2Count++;
onTransitionFromS1ToS2Latch.countDown();
}
@OnTransition
public void onTransition() {
onTransitionCount++;
onTransitionLatch.countDown();
}
@OnTransitionEnd
public void onTransitionEnd() {
onTransitionEndCount++;
onTransitionEndLatch.countDown();
}
@OnTransitionStart
public void onTransitionStart() {
onTransitionStartCount++;
onTransitionStartLatch.countDown();
}
@OnStateChanged(source = "S1", target = "S2")
public void onStateChangedFromS1ToS2() {
onStateChangedFromS1ToS2Count++;
onStateChangedFromS1ToS2Latch.countDown();
}
@OnStateChanged
public void onStateChanged() {
onStateChangedCount++;
onStateChangedLatch.countDown();
}
@OnStateMachineStart
public void onStateMachineStart() {
onStateMachineStartLatch.countDown();
onStateMachineStartCount++;
}
@OnStateMachineStart
public void onStateMachineStartWithParam(StateMachine<TestStates,TestEvents> machine) {
}
@OnStateMachineStop
public void onStateMachineStop() {
onStateMachineStopLatch.countDown();
onStateMachineStopCount++;
}
@OnStateMachineStop
public void onStateMachineStopWithParam(StateMachine<TestStates,TestEvents> machine) {
}
public void reset(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) {
onTransitionFromS1ToS2Latch = new CountDownLatch(a1);
onTransitionLatch = new CountDownLatch(a2);
onStateChangedFromS1ToS2Latch = new CountDownLatch(a3);
onStateChangedLatch = new CountDownLatch(a4);
onTransitionEndLatch = new CountDownLatch(a5);
onTransitionStartLatch = new CountDownLatch(a6);
onStateMachineStartLatch = new CountDownLatch(a7);
onStateMachineStopLatch = new CountDownLatch(a8);
onTransitionFromS1ToS2Count = 0;
onTransitionCount = 0;
onStateChangedFromS1ToS2Count = 0;
onStateChangedCount = 0;
onTransitionEndCount = 0;
onTransitionStartCount = 0;
onStateMachineStartCount = 0;
onStateMachineStopCount = 0;
}
}
@WithStateMachine
static class Bean2 {
CountDownLatch onMethod1Latch = new CountDownLatch(1);
CountDownLatch onMethod2Latch = new CountDownLatch(1);
Map<String, Object> headers;
ExtendedState extendedState;
Object variable;
@OnTransition(source = "S1", target = "S2")
public void method1(@EventHeaders Map<String, Object> headers, ExtendedState extendedState) {
this.headers = headers;
extendedState.getVariables().put("foo", "jee");
this.extendedState = extendedState;
onMethod1Latch.countDown();
}
@OnTransition(source = "S2", target = "S3")
public void method2(@EventHeaders Map<String, Object> headers, ExtendedState extendedState) {
variable = extendedState.getVariables().get("foo");
onMethod2Latch.countDown();
}
}
@WithStateMachine
static class Bean3 {
CountDownLatch onStateChangedLatch = new CountDownLatch(1);
@OnStateChanged
public void onStateChanged() {
onStateChangedLatch.countDown();
}
}
@WithStateMachine
static class Bean4 {
CountDownLatch onStateEntryLatch = new CountDownLatch(1);
CountDownLatch onStateExitLatch = new CountDownLatch(1);
int onStateEntryCount = 0;
int onStateExitCount = 0;
@OnStateEntry
public void onStateEntry() {
onStateEntryCount++;
onStateEntryLatch.countDown();
}
@OnStateExit
public void onStateExit() {
onStateExitCount++;
onStateExitLatch.countDown();
}
public void reset(int a1, int a2) {
onStateEntryCount = 0;
onStateExitCount = 0;
onStateEntryLatch = new CountDownLatch(a1);
onStateExitLatch = new CountDownLatch(a2);
}
}
@WithStateMachine
static class Bean5 {
CountDownLatch onExtendedStateChanged1Latch = new CountDownLatch(1);
CountDownLatch onExtendedStateChanged2Latch = new CountDownLatch(1);
CountDownLatch onExtendedStateChangedKeyV2Latch = new CountDownLatch(1);
int onExtendedStateChanged1Count = 0;
int onExtendedStateChanged2Count = 0;
Object onExtendedStateChanged2Value = null;
int onExtendedStateChangedKeyV2Count = 0;
@OnExtendedStateChanged
public void onExtendedStateChanged1() {
onExtendedStateChanged1Count++;
onExtendedStateChanged1Latch.countDown();
}
@OnExtendedStateChanged
public void onExtendedStateChanged2(@ExtendedStateVariable("V1") Object value) {
onExtendedStateChanged2Value = value;
onExtendedStateChanged2Count++;
onExtendedStateChanged2Latch.countDown();
}
@OnExtendedStateChanged(key = "V2")
public void onExtendedStateChangedKeyV2() {
onExtendedStateChangedKeyV2Count++;
onExtendedStateChangedKeyV2Latch.countDown();
}
public void reset(int a1, int a2, int a3) {
onExtendedStateChanged1Latch = new CountDownLatch(a1);
onExtendedStateChanged2Latch = new CountDownLatch(a2);
onExtendedStateChangedKeyV2Latch = new CountDownLatch(a3);
onExtendedStateChanged1Count = 0;
onExtendedStateChanged2Count = 0;
onExtendedStateChanged2Value = null;
onExtendedStateChangedKeyV2Count = 0;
}
}
@WithStateMachine
static class Bean6 {
CountDownLatch onEventNotAccepted1Latch = new CountDownLatch(1);
CountDownLatch onEventNotAccepted2Latch = new CountDownLatch(1);
CountDownLatch onEventNotAccepted3Latch = new CountDownLatch(1);
CountDownLatch onEventNotAccepted4Latch = new CountDownLatch(1);
CountDownLatch onEventNotAccepted5Latch = new CountDownLatch(1);
Message<TestEvents> onEventNotAccepted4Message;
@OnEventNotAccepted
public void onEventNotAccepted1() {
onEventNotAccepted1Latch.countDown();
}
@OnEventNotAccepted(event = "E1")
public void onEventNotAccepted2() {
onEventNotAccepted2Latch.countDown();
}
@OnEventNotAccepted(event = "E4")
public void onEventNotAccepted3() {
onEventNotAccepted3Latch.countDown();
}
@OnEventNotAccepted()
public void onEventNotAccepted4(Message<TestEvents> message) {
onEventNotAccepted4Message = message;
onEventNotAccepted4Latch.countDown();
}
@OnEventNotAccepted(event = {"E1", "E4"})
public void onEventNotAccepted5() {
onEventNotAccepted5Latch.countDown();
}
void reset() {
onEventNotAccepted1Latch = new CountDownLatch(1);
onEventNotAccepted2Latch = new CountDownLatch(1);
onEventNotAccepted3Latch = new CountDownLatch(1);
onEventNotAccepted4Latch = new CountDownLatch(1);
onEventNotAccepted4Message = null;
}
}
@WithStateMachine
static class Bean7 {
CountDownLatch OnStateMachineError1Latch = new CountDownLatch(1);
CountDownLatch OnStateMachineError2Latch = new CountDownLatch(1);
Exception OnStateMachineError2Exception;
@OnStateMachineError
public void OnStateMachineError1() {
OnStateMachineError1Latch.countDown();
}
@OnStateMachineError
public void OnStateMachineError2(Exception e) {
OnStateMachineError2Exception = e;
OnStateMachineError2Latch.countDown();
}
}
@WithStateMachine
static class Bean8 {
CountDownLatch OnTransition1Latch = new CountDownLatch(2);
CountDownLatch OnTransition2Latch = new CountDownLatch(1);
@OnTransition
public void OnTransition1() {
OnTransition1Latch.countDown();
}
@OnTransition(target = "SF")
public void OnTransition2() {
OnTransition2Latch.countDown();
}
}
@WithStateMachine
static class Bean9 {
CountDownLatch OnTransition1Latch = new CountDownLatch(1);
CountDownLatch OnStateEntry1Latch = new CountDownLatch(2);
@OnTransition(target = "S21")
public void OnTransition1() {
OnTransition1Latch.countDown();
}
@OnStateEntry(target = "S21")
public void OnStateEntry1() {
OnStateEntry1Latch.countDown();
}
}
@WithStateMachine
static class Bean10 {
CountDownLatch OnTransition1Latch = new CountDownLatch(1);
CountDownLatch OnStateEntry1Latch = new CountDownLatch(2);
@OnTransition(target = "S21")
public void OnTransition1() {
OnTransition1Latch.countDown();
}
@OnStateEntry(target = "S21")
public void OnStateEntry1() {
OnStateEntry1Latch.countDown();
}
}
@Configuration
static class BeanConfig1 {
@Bean
public Bean1 bean1() {
return new Bean1();
}
}
@Configuration
static class BeanConfig2 {
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
@Configuration
static class BeanConfig3 {
@Bean
public Bean3 bean3() {
return new Bean3();
}
}
@Configuration
static class BeanConfig4 {
@Bean
public Bean4 bean4() {
return new Bean4();
}
}
@Configuration
static class BeanConfig5 {
@Bean
public Bean5 bean5() {
return new Bean5();
}
}
@Configuration
static class BeanConfig6 {
@Bean
public Bean6 bean6() {
return new Bean6();
}
}
@Configuration
static class BeanConfig7 {
@Bean
public Bean7 bean7() {
return new Bean7();
}
}
@Configuration
static class BeanConfig8 {
@Bean
public Bean8 bean8() {
return new Bean8();
}
}
@Configuration
static class BeanConfig9 {
@Bean
public Bean9 bean9() {
return new Bean9();
}
}
@Configuration
static class BeanConfig10 {
@Bean
public Bean10 bean10() {
return new Bean10();
}
}
@Configuration
@EnableStateMachine(name = {StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, "fooMachine"})
static class Config1 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
@Override
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
states
.withStates()
.initial(TestStates.S1)
.end(TestStates.SF)
.states(EnumSet.allOf(TestStates.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
transitions
.withExternal()
.source(TestStates.S1)
.target(TestStates.S2)
.event(TestEvents.E1)
.guard(testGuard())
.action(testAction())
.action(extendedStateAction())
.and()
.withExternal()
.source(TestStates.S2)
.target(TestStates.S3)
.event(TestEvents.E2)
.and()
.withExternal()
.source(TestStates.S3)
.target(TestStates.S4)
.event(TestEvents.E3)
.and()
.withExternal()
.source(TestStates.S1)
.target(TestStates.SF)
.event(TestEvents.EF);
}
@Bean
public TestGuard testGuard() {
return new TestGuard();
}
@Bean
public TestAction testAction() {
return new TestAction();
}
@Bean
public Action<TestStates, TestEvents> extendedStateAction() {
return new Action<TestStates, TestEvents>() {
@Override
public void execute(StateContext<TestStates, TestEvents> context) {
String e1 = context.getMessageHeaders().get("V1", String.class);
if (e1 != null) {
context.getExtendedState().getVariables().put("V1", e1);
}
}
};
}
}
@Configuration
@EnableStateMachine
static class Config2 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
@Override
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
states
.withStates()
.initial(TestStates.S1)
.state(TestStates.S1)
.state(TestStates.S2)
.and()
.withStates()
.parent(TestStates.S2)
.initial(TestStates.S20)
.state(TestStates.S20)
.state(TestStates.S21)
.history(TestStates.SH, History.SHALLOW);
}
@Override
public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
transitions
.withExternal()
.source(TestStates.S1)
.target(TestStates.S2)
.event(TestEvents.E1)
.and()
.withExternal()
.source(TestStates.S20)
.target(TestStates.S21)
.event(TestEvents.E2)
.and()
.withExternal()
.source(TestStates.S2)
.target(TestStates.S1)
.event(TestEvents.E3)
.and()
.withExternal()
.source(TestStates.S1)
.target(TestStates.SH)
.event(TestEvents.E4);
}
}
@Configuration
@EnableStateMachine
static class Config3 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
@Override
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
states
.withStates()
.initial(TestStates.S1)
.state(TestStates.S1)
.state(TestStates.S2)
.and()
.withStates()
.parent(TestStates.S2)
.initial(TestStates.S20)
.state(TestStates.S20)
.end(TestStates.S21)
.history(TestStates.SH, History.SHALLOW);
}
@Override
public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
transitions
.withExternal()
.source(TestStates.S1)
.target(TestStates.S2)
.event(TestEvents.E1)
.and()
.withExternal()
.source(TestStates.S20)
.target(TestStates.S21)
.event(TestEvents.E2)
.and()
.withExternal()
.source(TestStates.S2)
.target(TestStates.S1)
.event(TestEvents.E3)
.and()
.withExternal()
.source(TestStates.S1)
.target(TestStates.SH)
.event(TestEvents.E4);
}
}
}