@WithStateMachine with factory and builder
- Add support so that @WithStateMachine can be used with machines build via @EnableStateMachineFactory or via manual builders. - Adding new annotation @EnableWithStateMachine to help handling needed context configuration. - Add tests and docs. - Fixes #292 - Fixes #224
This commit is contained in:
@@ -1144,6 +1144,15 @@ application context by using annotation `name` field.
|
||||
include::samples/DocsConfigurationSampleTests4.java[tags=snippetAA]
|
||||
----
|
||||
|
||||
Sometimes it is more convenient to use _machine id_ which is something
|
||||
user can set to better identify multiple instances. This id maps to
|
||||
_getId()_ method in a _StateMachine_ interface.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests4.java[tags=snippetAAAA]
|
||||
----
|
||||
|
||||
_@WithStateMachine_ can also be used as a meta-annotation as shown
|
||||
above. In this case you could annotate your bean with _WithMyBean_.
|
||||
|
||||
@@ -1158,6 +1167,29 @@ Return type of these methods doesn't matter and is effectively
|
||||
discard.
|
||||
====
|
||||
|
||||
=== Enabling Integration
|
||||
All features for _@WithStateMachine_ can be enabled by using
|
||||
annotation _@EnableWithStateMachine_ which simply imports needed
|
||||
configuration into Spring Application Context. Both
|
||||
_@EnableStateMachine_ and _@EnableStateMachineFactory_ are already
|
||||
annotated with this so there is no need for user to add it again.
|
||||
However if machine is build and configured without a use of
|
||||
configuration adapters, _@EnableWithStateMachine_ must be used order
|
||||
to use features with _@WithStateMachine_. Idea for this is shown
|
||||
below.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::samples/DocsConfigurationSampleTests4.java[tags=snippetAAAAA]
|
||||
----
|
||||
|
||||
[IMPORTANT]
|
||||
====
|
||||
If machine is not created as a _Bean_ then it is mandatory to set
|
||||
_BeanFactory_ for a machine as shown above. Otherwise machine will be
|
||||
unaware of handlers calling your _@WithStateMachine_ methods.
|
||||
====
|
||||
|
||||
=== Method Parameters
|
||||
Every annotation is supporting exactly same set of possible method
|
||||
parameters but runtime behaviour is different depending on an
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -23,6 +23,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -42,10 +43,18 @@ import org.springframework.stereotype.Component;
|
||||
public @interface WithStateMachine {
|
||||
|
||||
/**
|
||||
* The name of a state machine which annotated bean should be associated.
|
||||
* The name of a state machine bean which annotated bean should be associated.
|
||||
* Defaults to {@code stateMachine}
|
||||
*
|
||||
* @return the state machine bean name
|
||||
*/
|
||||
String name() default StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE;
|
||||
|
||||
/**
|
||||
* The id of a state machine which annotated bean should be associated.
|
||||
*
|
||||
* @return the state machine id
|
||||
* @see StateMachine#getId()
|
||||
*/
|
||||
String id() default "";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -27,7 +27,6 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.config.common.annotation.EnableAnnotationConfiguration;
|
||||
import org.springframework.statemachine.config.common.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineCommonConfiguration;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineConfiguration;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineConfigurationImportSelector;
|
||||
@@ -43,9 +42,9 @@ import org.springframework.statemachine.config.configuration.StateMachineConfigu
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@EnableAnnotationConfiguration
|
||||
@Import({ StateMachineConfigurationImportSelector.class, StateMachineCommonConfiguration.class,
|
||||
StateMachineConfiguration.class, ObjectPostProcessorConfiguration.class,
|
||||
StateMachineAnnotationPostProcessorConfiguration.class })
|
||||
@Import({ StateMachineConfigurationImportSelector.class, StateMachineCommonConfiguration.class, StateMachineConfiguration.class,
|
||||
ObjectPostProcessorConfiguration.class })
|
||||
@EnableWithStateMachine
|
||||
public @interface EnableStateMachine {
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -27,7 +27,6 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.config.common.annotation.EnableAnnotationConfiguration;
|
||||
import org.springframework.statemachine.config.common.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineCommonConfiguration;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineConfigurationImportSelector;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineFactoryConfiguration;
|
||||
@@ -43,9 +42,9 @@ import org.springframework.statemachine.config.configuration.StateMachineFactory
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@EnableAnnotationConfiguration
|
||||
@Import({ StateMachineConfigurationImportSelector.class, StateMachineCommonConfiguration.class,
|
||||
StateMachineFactoryConfiguration.class, ObjectPostProcessorConfiguration.class,
|
||||
StateMachineAnnotationPostProcessorConfiguration.class })
|
||||
@Import({ StateMachineConfigurationImportSelector.class, StateMachineCommonConfiguration.class, StateMachineFactoryConfiguration.class,
|
||||
ObjectPostProcessorConfiguration.class })
|
||||
@EnableWithStateMachine
|
||||
public @interface EnableStateMachineFactory {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2017 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.config;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.statemachine.annotation.WithStateMachine;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Annotation which enables features needed for {@link WithStateMachine}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Inherited
|
||||
@Documented
|
||||
@Component
|
||||
@Configuration
|
||||
@Import(StateMachineAnnotationPostProcessorConfiguration.class)
|
||||
public @interface EnableWithStateMachine {
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -48,6 +48,7 @@ import org.springframework.statemachine.config.configuration.StateMachineHandler
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.support.StateMachineUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Helper class which is used from a StateMachineObjectSupport to ease handling
|
||||
@@ -84,14 +85,15 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
Annotation metaAnnotation = handler.getMetaAnnotation();
|
||||
WithStateMachine withStateMachine = AnnotationUtils.findAnnotation(handler.getBeanClass(),
|
||||
WithStateMachine.class);
|
||||
String statemachineBeanName = withStateMachine.name();
|
||||
String key = metaAnnotation.annotationType().getName() + statemachineBeanName;
|
||||
List<CacheEntry> list = cache.get(key);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
cache.put(key, list);
|
||||
|
||||
if (StringUtils.hasText(withStateMachine.name())) {
|
||||
updateCache(metaAnnotation.annotationType().getName() + withStateMachine.name(),
|
||||
new CacheEntry(handler, annotation, metaAnnotation));
|
||||
}
|
||||
if (StringUtils.hasText(withStateMachine.id())) {
|
||||
updateCache(metaAnnotation.annotationType().getName() + withStateMachine.id(),
|
||||
new CacheEntry(handler, annotation, metaAnnotation));
|
||||
}
|
||||
list.add(new CacheEntry(handler, annotation, metaAnnotation));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +105,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
}
|
||||
|
||||
public void callOnStateChanged(String stateMachineId, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnStateChanged.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -120,6 +125,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
}
|
||||
|
||||
public void callOnStateEntry(String stateMachineId, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnStateEntry.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -137,6 +145,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
}
|
||||
|
||||
public void callOnStateExit(String stateMachineId, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnStateExit.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -154,6 +165,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
}
|
||||
|
||||
public void callOnEventNotAccepted(String stateMachineId, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnEventNotAccepted.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -175,6 +189,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
|
||||
|
||||
public void callOnTransitionStart(String stateMachineId, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnTransitionStart.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -192,6 +209,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
}
|
||||
|
||||
public void callOnTransition(String stateMachineId, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnTransition.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -209,6 +229,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
}
|
||||
|
||||
public void callOnTransitionEnd(String stateMachineId, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnTransitionEnd.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -226,6 +249,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
}
|
||||
|
||||
public void callOnStateMachineStart(String stateMachineId, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnStateMachineStart.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -239,6 +265,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
}
|
||||
|
||||
public void callOnStateMachineStop(String stateMachineId, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnStateMachineStop.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -252,6 +281,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
}
|
||||
|
||||
public void callOnStateMachineError(String stateMachineId, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnStateMachineError.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -265,6 +297,9 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
}
|
||||
|
||||
public void callOnExtendedStateChanged(String stateMachineId, Object key, Object value, StateContext<S, E> stateContext) {
|
||||
if (!StringUtils.hasText(stateMachineId)) {
|
||||
return;
|
||||
}
|
||||
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
|
||||
String cacheKey = OnExtendedStateChanged.class.getName() + stateMachineId;
|
||||
List<CacheEntry> list = getCacheEntries(cacheKey);
|
||||
@@ -279,6 +314,15 @@ public class StateMachineHandlerCallHelper<S, E> implements InitializingBean, Be
|
||||
getStateMachineHandlerResults(handlersList, stateContext);
|
||||
}
|
||||
|
||||
private void updateCache(String key, CacheEntry cacheEntry) {
|
||||
List<CacheEntry> list = cache.get(key);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
cache.put(key, list);
|
||||
}
|
||||
list.add(cacheEntry);
|
||||
}
|
||||
|
||||
private synchronized List<CacheEntry> getCacheEntries(String cacheKey) {
|
||||
if (stateMachineHandlerApplicationListener != null) {
|
||||
Long l = stateMachineHandlerApplicationListener.getLastRefreshTime();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -138,6 +138,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyStateChanged(StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnStateChanged(getBeanName(), stateContext);
|
||||
stateMachineHandlerCallHelper.callOnStateChanged(stateContext.getStateMachine().getId(), stateContext);
|
||||
stateListener.stateChanged(stateContext.getSource(), stateContext.getTarget());
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
@@ -154,6 +155,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyStateEntered(StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnStateEntry(getBeanName(), stateContext);
|
||||
stateMachineHandlerCallHelper.callOnStateEntry(stateContext.getStateMachine().getId(), stateContext);
|
||||
stateListener.stateEntered(stateContext.getTarget());
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
@@ -170,6 +172,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyStateExited(StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnStateExit(getBeanName(), stateContext);
|
||||
stateMachineHandlerCallHelper.callOnStateExit(stateContext.getStateMachine().getId(), stateContext);
|
||||
stateListener.stateExited(stateContext.getSource());
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
@@ -186,6 +189,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyEventNotAccepted(StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnEventNotAccepted(getBeanName(), stateContext);
|
||||
stateMachineHandlerCallHelper.callOnEventNotAccepted(stateContext.getStateMachine().getId(), stateContext);
|
||||
stateListener.eventNotAccepted(stateContext.getMessage());
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
@@ -202,6 +206,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyTransitionStart(StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnTransitionStart(getBeanName(), stateContext);
|
||||
stateMachineHandlerCallHelper.callOnTransitionStart(stateContext.getStateMachine().getId(), stateContext);
|
||||
stateListener.transitionStarted(stateContext.getTransition());
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
@@ -218,6 +223,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyTransition(StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnTransition(getBeanName(), stateContext);
|
||||
stateMachineHandlerCallHelper.callOnTransition(stateContext.getStateMachine().getId(), stateContext);
|
||||
stateListener.transition(stateContext.getTransition());
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
@@ -234,6 +240,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyTransitionEnd(StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnTransitionEnd(getBeanName(), stateContext);
|
||||
stateMachineHandlerCallHelper.callOnTransitionEnd(stateContext.getStateMachine().getId(), stateContext);
|
||||
stateListener.transitionEnded(stateContext.getTransition());
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
@@ -250,6 +257,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyStateMachineStarted(StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnStateMachineStart(getBeanName(), stateContext);
|
||||
stateMachineHandlerCallHelper.callOnStateMachineStart(stateContext.getStateMachine().getId(), stateContext);
|
||||
stateListener.stateMachineStarted(stateContext.getStateMachine());
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
@@ -266,6 +274,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyStateMachineStopped(StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnStateMachineStop(getBeanName(), stateContext);
|
||||
stateMachineHandlerCallHelper.callOnStateMachineStop(stateContext.getStateMachine().getId(), stateContext);
|
||||
stateListener.stateMachineStopped(stateContext.getStateMachine());
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
@@ -282,6 +291,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyStateMachineError(StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnStateMachineError(getBeanName(), stateContext);
|
||||
stateMachineHandlerCallHelper.callOnStateMachineError(stateContext.getStateMachine().getId(), stateContext);
|
||||
stateListener.stateMachineError(stateContext.getStateMachine(), stateContext.getException());
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
@@ -298,6 +308,7 @@ public abstract class StateMachineObjectSupport<S, E> extends LifecycleObjectSup
|
||||
protected void notifyExtendedStateChanged(Object key, Object value, StateContext<S, E> stateContext) {
|
||||
try {
|
||||
stateMachineHandlerCallHelper.callOnExtendedStateChanged(getBeanName(), key, value, stateContext);
|
||||
stateMachineHandlerCallHelper.callOnExtendedStateChanged(stateContext.getStateMachine().getId(), key, value, stateContext);
|
||||
stateListener.extendedStateChanged(key, value);
|
||||
stateListener.stateContext(stateContext);
|
||||
if (contextEventsEnabled) {
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2017 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.Matchers.contains;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.config.EnableWithStateMachine;
|
||||
import org.springframework.statemachine.config.StateMachineBuilder;
|
||||
import org.springframework.statemachine.config.StateMachineBuilder.Builder;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration;
|
||||
import org.springframework.statemachine.config.configurers.ConfigurationConfigurer;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MethodAnnotationWithBuilderTests extends AbstractStateMachineTests {
|
||||
|
||||
@Test
|
||||
public void testMethodAnnotations1() throws Exception {
|
||||
context.register(BeanConfig1.class, StateMachineAnnotationPostProcessorConfiguration.class);
|
||||
context.refresh();
|
||||
|
||||
Bean1 bean1 = context.getBean(Bean1.class);
|
||||
|
||||
StateMachine<TestStates,TestEvents> machine = context.getBean(StateMachine.class);
|
||||
machine.start();
|
||||
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
machine.sendEvent(TestEvents.E1);
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S2));
|
||||
assertThat(bean1.onStateChangedLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodAnnotations2() throws Exception {
|
||||
context.register(BeanConfig2.class);
|
||||
context.refresh();
|
||||
|
||||
Bean1 bean1 = context.getBean(Bean1.class);
|
||||
|
||||
StateMachine<TestStates,TestEvents> machine = context.getBean(StateMachine.class);
|
||||
machine.start();
|
||||
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
machine.sendEvent(TestEvents.E1);
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S2));
|
||||
assertThat(bean1.onStateChangedLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodAnnotations3() throws Exception {
|
||||
context.register(BeanConfig1.class, StateMachineAnnotationPostProcessorConfiguration.class);
|
||||
context.refresh();
|
||||
|
||||
Bean1 bean1 = context.getBean(Bean1.class);
|
||||
|
||||
StateMachine<TestStates,TestEvents> machine = buildMachine(context);
|
||||
machine.start();
|
||||
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
machine.sendEvent(TestEvents.E1);
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S2));
|
||||
assertThat(bean1.onStateChangedLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodAnnotations4() throws Exception {
|
||||
context.register(BeanConfig3.class);
|
||||
context.refresh();
|
||||
|
||||
Bean2 bean2 = context.getBean(Bean2.class);
|
||||
|
||||
StateMachine<TestStates,TestEvents> machine = buildMachine(context);
|
||||
machine.start();
|
||||
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
machine.sendEvent(TestEvents.E1);
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S2));
|
||||
assertThat(bean2.onStateChangedLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
}
|
||||
|
||||
@WithStateMachine(id = "xxx")
|
||||
static class Bean1 {
|
||||
|
||||
CountDownLatch onStateChangedLatch = new CountDownLatch(1);
|
||||
|
||||
@OnStateChanged
|
||||
public void onStateChanged() {
|
||||
onStateChangedLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@WithStateMachine(name = "", id = "xxx")
|
||||
static class Bean2 {
|
||||
|
||||
CountDownLatch onStateChangedLatch = new CountDownLatch(1);
|
||||
|
||||
@OnStateChanged
|
||||
public void onStateChanged() {
|
||||
onStateChangedLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class BeanConfig1 {
|
||||
|
||||
@Bean
|
||||
public Bean1 bean1() {
|
||||
return new Bean1();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StateMachine<TestStates,TestEvents> stateMachine() throws Exception {
|
||||
return buildMachine(null);
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWithStateMachine
|
||||
static class BeanConfig2 {
|
||||
|
||||
@Bean
|
||||
public Bean1 bean1() {
|
||||
return new Bean1();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StateMachine<TestStates,TestEvents> stateMachine() throws Exception {
|
||||
return buildMachine(null);
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWithStateMachine
|
||||
static class BeanConfig3 {
|
||||
|
||||
@Bean
|
||||
public Bean2 bean2() {
|
||||
return new Bean2();
|
||||
}
|
||||
}
|
||||
|
||||
private static StateMachine<TestStates,TestEvents> buildMachine(BeanFactory beanFactory) throws Exception {
|
||||
Builder<TestStates,TestEvents> builder = StateMachineBuilder.builder();
|
||||
|
||||
ConfigurationConfigurer<TestStates, TestEvents> withConfiguration = builder.configureConfiguration().withConfiguration();
|
||||
withConfiguration.machineId("xxx");
|
||||
if (beanFactory != null) {
|
||||
withConfiguration.beanFactory(beanFactory);
|
||||
}
|
||||
|
||||
builder.configureStates()
|
||||
.withStates()
|
||||
.initial(TestStates.S1)
|
||||
.states(EnumSet.allOf(TestStates.class));
|
||||
|
||||
builder.configureTransitions()
|
||||
.withExternal()
|
||||
.source(TestStates.S1)
|
||||
.target(TestStates.S2)
|
||||
.event(TestEvents.E1);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotationConfigApplicationContext buildContext() {
|
||||
return new AnnotationConfigApplicationContext();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2017 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.Matchers.contains;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.EnumSet;
|
||||
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.statemachine.AbstractStateMachineTests;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.StateMachineFactory;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MethodAnnotationWithFactoryTests extends AbstractStateMachineTests {
|
||||
|
||||
@Test
|
||||
public void testMethodAnnotations1() throws Exception {
|
||||
context.register(BeanConfig1.class, Config1.class);
|
||||
context.refresh();
|
||||
|
||||
Bean1 bean1 = context.getBean(Bean1.class);
|
||||
|
||||
StateMachineFactory<TestStates,TestEvents> factory =
|
||||
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINEFACTORY, StateMachineFactory.class);
|
||||
StateMachine<TestStates,TestEvents> machine = factory.getStateMachine("xxx");
|
||||
machine.start();
|
||||
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
machine.sendEvent(TestEvents.E1);
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S2));
|
||||
assertThat(bean1.onStateChangedLatch.await(1, TimeUnit.SECONDS), is(true));
|
||||
}
|
||||
|
||||
@WithStateMachine(name = "xxx")
|
||||
static class Bean1 {
|
||||
|
||||
CountDownLatch onStateChangedLatch = new CountDownLatch(1);
|
||||
|
||||
@OnStateChanged
|
||||
public void onStateChanged() {
|
||||
onStateChangedLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class BeanConfig1 {
|
||||
|
||||
@Bean
|
||||
public Bean1 bean1() {
|
||||
return new Bean1();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachineFactory
|
||||
static class Config1 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(TestStates.S1)
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotationConfigApplicationContext buildContext() {
|
||||
return new AnnotationConfigApplicationContext();
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests;
|
||||
import org.springframework.statemachine.ExtendedState;
|
||||
@@ -37,6 +38,8 @@ import org.springframework.statemachine.annotation.OnStateMachineStart;
|
||||
import org.springframework.statemachine.annotation.OnStateMachineStop;
|
||||
import org.springframework.statemachine.annotation.OnTransition;
|
||||
import org.springframework.statemachine.annotation.WithStateMachine;
|
||||
import org.springframework.statemachine.config.StateMachineBuilder;
|
||||
import org.springframework.statemachine.config.StateMachineBuilder.Builder;
|
||||
|
||||
public class DocsConfigurationSampleTests4 extends AbstractStateMachineTests {
|
||||
|
||||
@@ -60,6 +63,16 @@ public class DocsConfigurationSampleTests4 extends AbstractStateMachineTests {
|
||||
}
|
||||
// end::snippetAA[]
|
||||
|
||||
// tag::snippetAAAA[]
|
||||
@WithStateMachine(id = "myMachineId")
|
||||
public class Bean16 {
|
||||
|
||||
@OnTransition
|
||||
public void anyTransition() {
|
||||
}
|
||||
}
|
||||
// end::snippetAAAA[]
|
||||
|
||||
// tag::snippetAAA[]
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -68,6 +81,39 @@ public class DocsConfigurationSampleTests4 extends AbstractStateMachineTests {
|
||||
}
|
||||
// end::snippetAAA[]
|
||||
|
||||
|
||||
// tag::snippetAAAAA[]
|
||||
public static StateMachine<String, String> buildMachine(BeanFactory beanFactory) throws Exception {
|
||||
Builder<String, String> builder = StateMachineBuilder.builder();
|
||||
|
||||
builder.configureConfiguration()
|
||||
.withConfiguration()
|
||||
.machineId("myMachineId")
|
||||
.beanFactory(beanFactory);
|
||||
|
||||
builder.configureStates()
|
||||
.withStates()
|
||||
.initial("S1")
|
||||
.state("S2");
|
||||
|
||||
builder.configureTransitions()
|
||||
.withExternal()
|
||||
.source("S1")
|
||||
.target("S2")
|
||||
.event("E1");
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@WithStateMachine(id = "myMachineId")
|
||||
static class Bean17 {
|
||||
|
||||
@OnStateChanged
|
||||
public void onStateChanged() {
|
||||
}
|
||||
}
|
||||
// end::snippetAAAAA[]
|
||||
|
||||
// tag::snippetB[]
|
||||
@WithStateMachine
|
||||
public class Bean3 {
|
||||
|
||||
Reference in New Issue
Block a user