From 58e9f01aaf326e8882490bff736bc45e556b5984 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Thu, 5 Nov 2015 13:46:13 +0000 Subject: [PATCH] Association with @EnableStateMachine and @WithStateMachine - Fix bug where multiple machines and beans with @WithStateMachine didn't properly separate calling methods with @OnTransition. - Some polish - Fixes #116 --- .../config/AbstractStateMachineFactory.java | 21 +- .../config/ObjectStateMachineFactory.java | 6 +- ...eAnnotationPostProcessorConfiguration.java | 2 +- .../StateMachineConfiguration.java | 10 +- .../MethodAnnotationPostProcessor.java | 3 +- ...chineActivatorAnnotationPostProcessor.java | 4 +- .../StateMachineAnnotationPostProcessor.java | 2 +- .../processor/StateMachineHandler.java | 25 ++- .../StateMachineOnTransitionHandler.java | 5 +- .../support/AbstractStateMachine.java | 12 +- .../support/StateMachineObjectSupport.java | 20 +- .../annotation/ClassAnnotationTests.java | 192 ++++++++++++++++++ 12 files changed, 278 insertions(+), 24 deletions(-) create mode 100644 spring-statemachine-core/src/test/java/org/springframework/statemachine/annotation/ClassAnnotationTests.java diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/AbstractStateMachineFactory.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/AbstractStateMachineFactory.java index baf4354c..413000e3 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/AbstractStateMachineFactory.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/AbstractStateMachineFactory.java @@ -25,6 +25,7 @@ import java.util.Map.Entry; import java.util.Stack; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.SmartLifecycle; import org.springframework.core.task.TaskExecutor; import org.springframework.messaging.Message; @@ -77,7 +78,7 @@ import org.springframework.util.ObjectUtils; * @param the type of event */ public abstract class AbstractStateMachineFactory extends LifecycleObjectSupport implements - StateMachineFactory { + StateMachineFactory, BeanNameAware { private final StateMachineTransitions stateMachineTransitions; @@ -89,6 +90,8 @@ public abstract class AbstractStateMachineFactory extends LifecycleObjectS private boolean handleAutostartup = false; + private String beanName; + /** * Instantiates a new enum state machine factory. * @@ -102,6 +105,11 @@ public abstract class AbstractStateMachineFactory extends LifecycleObjectS this.stateMachineTransitions = stateMachineTransitions; this.stateMachineStates = stateMachineStates; } + + @Override + public void setBeanName(String name) { + this.beanName = name; + } @SuppressWarnings("unchecked") @Override @@ -178,7 +186,7 @@ public abstract class AbstractStateMachineFactory extends LifecycleObjectS Transition initialTransition = new InitialTransition(rstate); StateMachine m = buildStateMachineInternal(states, new ArrayList>(), rstate, initialTransition, null, defaultExtendedState, null, contextEvents, resolveBeanFactory(), - resolveTaskExecutor(), resolveTaskScheduler()); + resolveTaskExecutor(), resolveTaskScheduler(), beanName); machine = m; } } else { @@ -196,7 +204,7 @@ public abstract class AbstractStateMachineFactory extends LifecycleObjectS if (machine instanceof LifecycleObjectSupport) { ((LifecycleObjectSupport)machine).setAutoStartup(stateMachineConfigurationConfig.isAutoStart()); } - + // set top-level machine as relay final StateMachine fmachine = machine; fmachine.getStateMachineAccessor().doWithAllRegions(new StateMachineFunction>() { @@ -536,8 +544,9 @@ public abstract class AbstractStateMachineFactory extends LifecycleObjectS } Transition initialTransition = new InitialTransition(initialState, initialAction); - StateMachine machine = buildStateMachineInternal(states, transitions, initialState, initialTransition, null, - defaultExtendedState, historyState, contextEvents, beanFactory, taskExecutor, taskScheduler); + StateMachine machine = buildStateMachineInternal(states, transitions, initialState, initialTransition, + null, defaultExtendedState, historyState, contextEvents, beanFactory, taskExecutor, taskScheduler, + beanName); return machine; } @@ -545,7 +554,7 @@ public abstract class AbstractStateMachineFactory extends LifecycleObjectS Collection> transitions, State initialState, Transition initialTransition, Message initialEvent, ExtendedState extendedState, PseudoState historyState, Boolean contextEventsEnabled, BeanFactory beanFactory, TaskExecutor taskExecutor, - TaskScheduler taskScheduler); + TaskScheduler taskScheduler, String beanName); protected abstract State buildStateInternal(S id, Collection deferred, Collection> entryActions, Collection> exitActions, PseudoState pseudoState); diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/ObjectStateMachineFactory.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/ObjectStateMachineFactory.java index f44aa31e..a196a95e 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/ObjectStateMachineFactory.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/ObjectStateMachineFactory.java @@ -18,6 +18,7 @@ package org.springframework.statemachine.config; import java.util.Collection; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanNameAware; import org.springframework.core.task.TaskExecutor; import org.springframework.messaging.Message; import org.springframework.scheduling.TaskScheduler; @@ -56,7 +57,7 @@ public class ObjectStateMachineFactory extends AbstractStateMachineFactory Collection> transitions, State initialState, Transition initialTransition, Message initialEvent, ExtendedState extendedState, PseudoState historyState, Boolean contextEventsEnabled, BeanFactory beanFactory, TaskExecutor taskExecutor, - TaskScheduler taskScheduler) { + TaskScheduler taskScheduler, String beanName) { ObjectStateMachine machine = new ObjectStateMachine(states, transitions, initialState, initialTransition, initialEvent, extendedState); machine.setHistoryState(historyState); @@ -72,6 +73,9 @@ public class ObjectStateMachineFactory extends AbstractStateMachineFactory if (taskScheduler != null) { machine.setTaskScheduler(taskScheduler);; } + if (machine instanceof BeanNameAware) { + ((BeanNameAware)machine).setBeanName(beanName); + } machine.afterPropertiesSet(); return machine; } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineAnnotationPostProcessorConfiguration.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineAnnotationPostProcessorConfiguration.java index 47cd03cc..82fedec1 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineAnnotationPostProcessorConfiguration.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineAnnotationPostProcessorConfiguration.java @@ -21,7 +21,7 @@ import org.springframework.statemachine.annotation.WithStateMachine; import org.springframework.statemachine.processor.StateMachineAnnotationPostProcessor; /** - * Configuration for annotation port processor which is needed i.e. when + * Configuration for annotation post processor which is needed i.e. when * {@link WithStateMachine} is used. * * @author Janne Valkealahti diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineConfiguration.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineConfiguration.java index 8b77f755..650e461f 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineConfiguration.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineConfiguration.java @@ -19,6 +19,7 @@ import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; +import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.context.SmartLifecycle; @@ -68,11 +69,12 @@ public class StateMachineConfiguration, E extends Enum> ext private static class StateMachineDelegatingFactoryBean, E extends Enum> extends BeanDelegatingFactoryBean,StateMachineConfigBuilder,StateMachineConfig> - implements SmartLifecycle { + implements SmartLifecycle, BeanNameAware { private String clazzName; private Boolean contextEvents; private SmartLifecycle lifecycle; + private String beanName; public StateMachineDelegatingFactoryBean(StateMachineConfigBuilder builder, Class> clazz, String clazzName, Boolean contextEvents) { @@ -80,6 +82,11 @@ public class StateMachineConfiguration, E extends Enum> ext this.clazzName = clazzName; this.contextEvents = contextEvents; } + + @Override + public void setBeanName(String name) { + this.beanName = name; + } @Override public void afterPropertiesSet() throws Exception { @@ -97,6 +104,7 @@ public class StateMachineConfiguration, E extends Enum> ext stateMachineConfigurationConfig, stateMachineTransitions, stateMachineStates); stateMachineFactory.setBeanFactory(getBeanFactory()); stateMachineFactory.setContextEventsEnabled(contextEvents); + stateMachineFactory.setBeanName(beanName); StateMachine stateMachine = stateMachineFactory.getStateMachine(); this.lifecycle = (SmartLifecycle) stateMachine; setObject(stateMachine); diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/MethodAnnotationPostProcessor.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/MethodAnnotationPostProcessor.java index 52b5ead1..9deb23f8 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/MethodAnnotationPostProcessor.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/MethodAnnotationPostProcessor.java @@ -34,6 +34,7 @@ public interface MethodAnnotationPostProcessor { * null. Caller of this method is then responsible to handle * newly created object. * + * @param beanClass the bean class * @param bean the bean * @param beanName the bean name * @param method the method @@ -41,6 +42,6 @@ public interface MethodAnnotationPostProcessor { * @param annotation the annotation * @return the post processed object */ - Object postProcess(Object bean, String beanName, Method method, T metaAnnotation, Annotation annotation); + Object postProcess(Class beanClass, Object bean, String beanName, Method method, T metaAnnotation, Annotation annotation); } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineActivatorAnnotationPostProcessor.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineActivatorAnnotationPostProcessor.java index 4c080d03..b6018fc3 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineActivatorAnnotationPostProcessor.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineActivatorAnnotationPostProcessor.java @@ -40,8 +40,8 @@ public class StateMachineActivatorAnnotationPostProcessor implements MethodAnnot } @Override - public Object postProcess(Object bean, String beanName, Method method, OnTransition metaAnnotation, Annotation annotation) { - StateMachineHandler handler = new StateMachineOnTransitionHandler(bean, method, metaAnnotation, annotation); + public Object postProcess(Class beanClass, Object bean, String beanName, Method method, OnTransition metaAnnotation, Annotation annotation) { + StateMachineHandler handler = new StateMachineOnTransitionHandler(beanClass, bean, method, metaAnnotation, annotation); Integer order = findOrder(bean, method); if (order != null) { diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineAnnotationPostProcessor.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineAnnotationPostProcessor.java index cddb45a2..60993361 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineAnnotationPostProcessor.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineAnnotationPostProcessor.java @@ -133,7 +133,7 @@ public class StateMachineAnnotationPostProcessor implements BeanPostProcessor, B .get(metaAnnotation.annotationType()) : null; if (postProcessor != null && shouldCreateHandler(annotation)) { - Object result = postProcessor.postProcess(bean, beanName, method, metaAnnotation, annotation); + Object result = postProcessor.postProcess(beanClass, bean, beanName, method, metaAnnotation, annotation); if (result != null && result instanceof StateMachineHandler) { String endpointBeanName = generateBeanName(beanName, method, annotation.annotationType()); diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineHandler.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineHandler.java index 40405934..15c90a32 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineHandler.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineHandler.java @@ -33,6 +33,8 @@ import org.springframework.statemachine.annotation.WithStateMachine; */ public class StateMachineHandler implements Ordered { + private final Class beanClass; + private final StateMachineRuntimeProcessor processor; private int order = Ordered.LOWEST_PRECEDENCE; @@ -40,30 +42,34 @@ public class StateMachineHandler implements Ordered { /** * Instantiates a new container handler. * + * @param beanClass the bean class * @param target the target bean * @param method the method */ - public StateMachineHandler(Object target, Method method) { - this(new MethodInvokingStateMachineRuntimeProcessor(target, method)); + public StateMachineHandler(Class beanClass, Object target, Method method) { + this(beanClass, new MethodInvokingStateMachineRuntimeProcessor(target, method)); } /** * Instantiates a new container handler. * + * @param beanClass the bean class * @param target the target bean * @param methodName the method name */ - public StateMachineHandler(Object target, String methodName) { - this(new MethodInvokingStateMachineRuntimeProcessor(target, methodName)); + public StateMachineHandler(Class beanClass, Object target, String methodName) { + this(beanClass, new MethodInvokingStateMachineRuntimeProcessor(target, methodName)); } /** * Instantiates a new container handler. * * @param the generic type + * @param beanClass the bean class * @param processor the processor */ - public StateMachineHandler(MethodInvokingStateMachineRuntimeProcessor processor) { + public StateMachineHandler(Class beanClass, MethodInvokingStateMachineRuntimeProcessor processor) { + this.beanClass = beanClass; this.processor = processor; } @@ -71,6 +77,15 @@ public class StateMachineHandler implements Ordered { public int getOrder() { return order; } + + /** + * Gets the bean class. + * + * @return the bean class + */ + public Class getBeanClass() { + return beanClass; + } /** * Sets the order used get value from {@link #getOrder()}. diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineOnTransitionHandler.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineOnTransitionHandler.java index 265bde3c..1d2d1734 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineOnTransitionHandler.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineOnTransitionHandler.java @@ -36,13 +36,14 @@ public class StateMachineOnTransitionHandler extends StateMachineHandler beanClass, Object target, Method method, OnTransition metaAnnotation, Annotation annotation) { + super(beanClass, target, method); this.metaAnnotation = metaAnnotation; this.annotation = annotation; } 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 a992b644..53d9caea 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 @@ -44,6 +44,7 @@ import org.springframework.statemachine.access.StateMachineAccess; import org.springframework.statemachine.access.StateMachineAccessor; import org.springframework.statemachine.access.StateMachineFunction; import org.springframework.statemachine.annotation.OnTransition; +import org.springframework.statemachine.annotation.WithStateMachine; import org.springframework.statemachine.listener.StateMachineListener; import org.springframework.statemachine.processor.StateMachineHandler; import org.springframework.statemachine.processor.StateMachineOnTransitionHandler; @@ -64,6 +65,7 @@ import org.springframework.statemachine.transition.TransitionKind; import org.springframework.statemachine.trigger.DefaultTriggerContext; import org.springframework.statemachine.trigger.Trigger; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -890,9 +892,9 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo Assert.state(beanFactory instanceof ListableBeanFactory, "Bean factory must be instance of ListableBeanFactory"); if (!handlersInitialized) { - Map handlersx = ((ListableBeanFactory) beanFactory) + Map handlersMap = ((ListableBeanFactory) beanFactory) .getBeansOfType(StateMachineOnTransitionHandler.class); - for (Entry entry : handlersx.entrySet()) { + for (Entry entry : handlersMap.entrySet()) { handlers.put(entry.getKey(), entry.getValue()); } handlersInitialized = true; @@ -901,9 +903,13 @@ public abstract class AbstractStateMachine extends StateMachineObjectSuppo List> handlersList = new ArrayList>(); for (Entry> entry : handlers.entrySet()) { + // add only matching names from beanName and WithStateMachine name field + WithStateMachine withStateMachine = AnnotationUtils.findAnnotation(entry.getValue().getBeanClass(), WithStateMachine.class); + if (withStateMachine == null || !ObjectUtils.nullSafeEquals(withStateMachine.name(), getBeanName())) { + continue; + } OnTransition metaAnnotation = entry.getValue().getMetaAnnotation(); Annotation annotation = entry.getValue().getAnnotation(); - if (transitionHandlerMatch(metaAnnotation, annotation, sourceState, targetState)) { handlersList.add(entry.getValue()); } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/StateMachineObjectSupport.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/StateMachineObjectSupport.java index b4d8614c..48d7a183 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/StateMachineObjectSupport.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/StateMachineObjectSupport.java @@ -20,6 +20,7 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.BeanNameAware; import org.springframework.core.OrderComparator; import org.springframework.messaging.Message; import org.springframework.statemachine.StateMachine; @@ -38,7 +39,7 @@ import org.springframework.util.Assert; * @param the type of state * @param the type of event */ -public abstract class StateMachineObjectSupport extends LifecycleObjectSupport { +public abstract class StateMachineObjectSupport extends LifecycleObjectSupport implements BeanNameAware { private static final Log log = LogFactory.getLog(StateMachineObjectSupport.class); @@ -52,7 +53,24 @@ public abstract class StateMachineObjectSupport extends LifecycleObjectSup private final StateMachineInterceptorList interceptors = new StateMachineInterceptorList(); + + private String beanName; + @Override + public void setBeanName(String name) { + beanName = name; + } + + /** + * Returns a bean name known to context per contract + * with {@link BeanNameAware}. + * + * @return a bean name + */ + protected String getBeanName() { + return beanName; + } + /** * Gets the state machine event publisher. * diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/annotation/ClassAnnotationTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/annotation/ClassAnnotationTests.java new file mode 100644 index 00000000..083ec6cf --- /dev/null +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/annotation/ClassAnnotationTests.java @@ -0,0 +1,192 @@ +/* + * 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.junit.Assert.assertThat; + +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.support.MessageBuilder; +import org.springframework.statemachine.AbstractStateMachineTests; +import org.springframework.statemachine.ObjectStateMachine; +import org.springframework.statemachine.annotation.OnTransition; +import org.springframework.statemachine.annotation.WithStateMachine; +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; + +public class ClassAnnotationTests extends AbstractStateMachineTests { + + @Test + @SuppressWarnings("unchecked") + public void testClassAnnotations() throws Exception { + AnnotationConfigApplicationContext context = + new AnnotationConfigApplicationContext(BaseConfig.class, BeanConfig.class, FooConfig.class, BarConfig.class); + + ObjectStateMachine fooMachine = + context.getBean("fooMachine", ObjectStateMachine.class); + + ObjectStateMachine barMachine = + context.getBean("barMachine", ObjectStateMachine.class); + + assertThat(context.containsBean("fooMachine"), is(true)); + assertThat(context.containsBean("barMachine"), is(true)); + fooMachine.start(); + barMachine.start(); + + FooBean fooBean = context.getBean(FooBean.class); + BarBean barBean = context.getBean(BarBean.class); + + fooBean.resetMethodLatch(); + + // this event should cause 'FooBean.fooMethod' to get called + fooMachine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build()); + + assertThat(fooBean.onFooMethodLatch.await(2, TimeUnit.SECONDS), is(true)); + assertThat(barBean.onBarMethodLatch.await(2, TimeUnit.SECONDS), is(false)); + + fooBean.resetMethodLatch(); + + // this event should cause 'BarBean.barMethod' to get called + barMachine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).build()); + + assertThat(fooBean.onFooMethodLatch.await(2, TimeUnit.SECONDS), is(false)); + assertThat(barBean.onBarMethodLatch.await(2, TimeUnit.SECONDS), is(true)); + + context.close(); + } + + @WithStateMachine(name = "fooMachine") + static class FooBean { + + CountDownLatch onFooMethodLatch; + + public void resetMethodLatch() { + onFooMethodLatch = new CountDownLatch(1); + } + + @OnTransition(source = "S1", target = "S2") + public void fooMethod() { + onFooMethodLatch.countDown(); + } + + } + + @WithStateMachine(name = "barMachine") + static class BarBean { + + CountDownLatch onBarMethodLatch = new CountDownLatch(1); + + @OnTransition(source = "S1", target = "S2") + public void barMethod() { + onBarMethodLatch.countDown(); + } + + } + + @Configuration + static class BeanConfig { + + @Bean + public FooBean fooBean() { + return new FooBean(); + } + + @Bean + public BarBean barBean() { + return new BarBean(); + } + + } + + @Configuration + @EnableStateMachine(name = "fooMachine") + static class FooConfig extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(TestStates.S1) + .state(TestStates.S2); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TestStates.S1) + .target(TestStates.S2) + .event(TestEvents.E1) + .guard(testGuard()) + .action(testAction()); + } + + @Bean + public TestGuard testGuard() { + return new TestGuard(); + } + + @Bean + public TestAction testAction() { + return new TestAction(); + } + + } + + @Configuration + @EnableStateMachine(name = "barMachine") + static class BarConfig extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(TestStates.S1) + .state(TestStates.S2); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TestStates.S1) + .target(TestStates.S2) + .event(TestEvents.E1) + .guard(testGuard()) + .action(testAction()); + } + + @Bean + public TestGuard testGuard() { + return new TestGuard(); + } + + @Bean + public TestAction testAction() { + return new TestAction(); + } + + } + +}