Skip to content

Commit 29e8cdd

Browse files
committed
@WithStateMachine with factory and builder
- Backport #292 - Backport #224 - 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. - Relates to #307
1 parent 17d977d commit 29e8cdd

File tree

10 files changed

+504
-21
lines changed

10 files changed

+504
-21
lines changed

docs/src/reference/asciidoc/sm.adoc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,15 @@ application context by using annotation `name` field.
11441144
include::samples/DocsConfigurationSampleTests4.java[tags=snippetAA]
11451145
----
11461146

1147+
Sometimes it is more convenient to use _machine id_ which is something
1148+
user can set to better identify multiple instances. This id maps to
1149+
_getId()_ method in a _StateMachine_ interface.
1150+
1151+
[source,java,indent=0]
1152+
----
1153+
include::samples/DocsConfigurationSampleTests4.java[tags=snippetAAAA]
1154+
----
1155+
11471156
_@WithStateMachine_ can also be used as a meta-annotation as shown
11481157
above. In this case you could annotate your bean with _WithMyBean_.
11491158

@@ -1158,6 +1167,29 @@ Return type of these methods doesn't matter and is effectively
11581167
discard.
11591168
====
11601169

1170+
=== Enabling Integration
1171+
All features for _@WithStateMachine_ can be enabled by using
1172+
annotation _@EnableWithStateMachine_ which simply imports needed
1173+
configuration into Spring Application Context. Both
1174+
_@EnableStateMachine_ and _@EnableStateMachineFactory_ are already
1175+
annotated with this so there is no need for user to add it again.
1176+
However if machine is build and configured without a use of
1177+
configuration adapters, _@EnableWithStateMachine_ must be used order
1178+
to use features with _@WithStateMachine_. Idea for this is shown
1179+
below.
1180+
1181+
[source,java,indent=0]
1182+
----
1183+
include::samples/DocsConfigurationSampleTests4.java[tags=snippetAAAAA]
1184+
----
1185+
1186+
[IMPORTANT]
1187+
====
1188+
If machine is not created as a _Bean_ then it is mandatory to set
1189+
_BeanFactory_ for a machine as shown above. Otherwise machine will be
1190+
unaware of handlers calling your _@WithStateMachine_ methods.
1191+
====
1192+
11611193
=== Method Parameters
11621194
Every annotation is supporting exactly same set of possible method
11631195
parameters but runtime behaviour is different depending on an

spring-statemachine-core/src/main/java/org/springframework/statemachine/annotation/WithStateMachine.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
2323
import java.lang.annotation.Target;
2424

2525
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.statemachine.StateMachine;
2627
import org.springframework.statemachine.StateMachineSystemConstants;
2728
import org.springframework.stereotype.Component;
2829

@@ -42,10 +43,18 @@
4243
public @interface WithStateMachine {
4344

4445
/**
45-
* The name of a state machine which annotated bean should be associated.
46+
* The name of a state machine bean which annotated bean should be associated.
47+
* Defaults to {@code stateMachine}
4648
*
4749
* @return the state machine bean name
4850
*/
4951
String name() default StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE;
5052

53+
/**
54+
* The id of a state machine which annotated bean should be associated.
55+
*
56+
* @return the state machine id
57+
* @see StateMachine#getId()
58+
*/
59+
String id() default "";
5160
}

spring-statemachine-core/src/main/java/org/springframework/statemachine/config/EnableStateMachine.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@
2727
import org.springframework.statemachine.StateMachineSystemConstants;
2828
import org.springframework.statemachine.config.common.annotation.EnableAnnotationConfiguration;
2929
import org.springframework.statemachine.config.common.annotation.configuration.ObjectPostProcessorConfiguration;
30-
import org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration;
3130
import org.springframework.statemachine.config.configuration.StateMachineCommonConfiguration;
3231
import org.springframework.statemachine.config.configuration.StateMachineConfiguration;
3332
import org.springframework.statemachine.config.configuration.StateMachineConfigurationImportSelector;
@@ -43,9 +42,9 @@
4342
@Target(ElementType.TYPE)
4443
@Documented
4544
@EnableAnnotationConfiguration
46-
@Import({ StateMachineConfigurationImportSelector.class, StateMachineCommonConfiguration.class,
47-
StateMachineConfiguration.class, ObjectPostProcessorConfiguration.class,
48-
StateMachineAnnotationPostProcessorConfiguration.class })
45+
@Import({ StateMachineConfigurationImportSelector.class, StateMachineCommonConfiguration.class, StateMachineConfiguration.class,
46+
ObjectPostProcessorConfiguration.class })
47+
@EnableWithStateMachine
4948
public @interface EnableStateMachine {
5049

5150
/**

spring-statemachine-core/src/main/java/org/springframework/statemachine/config/EnableStateMachineFactory.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@
2727
import org.springframework.statemachine.StateMachineSystemConstants;
2828
import org.springframework.statemachine.config.common.annotation.EnableAnnotationConfiguration;
2929
import org.springframework.statemachine.config.common.annotation.configuration.ObjectPostProcessorConfiguration;
30-
import org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration;
3130
import org.springframework.statemachine.config.configuration.StateMachineCommonConfiguration;
3231
import org.springframework.statemachine.config.configuration.StateMachineConfigurationImportSelector;
3332
import org.springframework.statemachine.config.configuration.StateMachineFactoryConfiguration;
@@ -43,9 +42,9 @@
4342
@Target(ElementType.TYPE)
4443
@Documented
4544
@EnableAnnotationConfiguration
46-
@Import({ StateMachineConfigurationImportSelector.class, StateMachineCommonConfiguration.class,
47-
StateMachineFactoryConfiguration.class, ObjectPostProcessorConfiguration.class,
48-
StateMachineAnnotationPostProcessorConfiguration.class })
45+
@Import({ StateMachineConfigurationImportSelector.class, StateMachineCommonConfiguration.class, StateMachineFactoryConfiguration.class,
46+
ObjectPostProcessorConfiguration.class })
47+
@EnableWithStateMachine
4948
public @interface EnableStateMachineFactory {
5049

5150
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.statemachine.config;
17+
18+
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Inherited;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
24+
25+
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.context.annotation.Import;
27+
import org.springframework.statemachine.annotation.WithStateMachine;
28+
import org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration;
29+
import org.springframework.stereotype.Component;
30+
31+
/**
32+
* Annotation which enables features needed for {@link WithStateMachine}.
33+
*
34+
* @author Janne Valkealahti
35+
*
36+
*/
37+
@Retention(RetentionPolicy.RUNTIME)
38+
@Target(ElementType.TYPE)
39+
@Inherited
40+
@Documented
41+
@Component
42+
@Configuration
43+
@Import(StateMachineAnnotationPostProcessorConfiguration.class)
44+
public @interface EnableWithStateMachine {
45+
}

spring-statemachine-core/src/main/java/org/springframework/statemachine/processor/StateMachineHandlerCallHelper.java

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2016 the original author or authors.
2+
* Copyright 2015-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -48,6 +48,7 @@
4848
import org.springframework.statemachine.state.State;
4949
import org.springframework.statemachine.support.StateMachineUtils;
5050
import org.springframework.util.Assert;
51+
import org.springframework.util.StringUtils;
5152

5253
/**
5354
* Helper class which is used from a StateMachineObjectSupport to ease handling
@@ -84,14 +85,15 @@ public void afterPropertiesSet() throws Exception {
8485
Annotation metaAnnotation = handler.getMetaAnnotation();
8586
WithStateMachine withStateMachine = AnnotationUtils.findAnnotation(handler.getBeanClass(),
8687
WithStateMachine.class);
87-
String statemachineBeanName = withStateMachine.name();
88-
String key = metaAnnotation.annotationType().getName() + statemachineBeanName;
89-
List<CacheEntry> list = cache.get(key);
90-
if (list == null) {
91-
list = new ArrayList<>();
92-
cache.put(key, list);
88+
89+
if (StringUtils.hasText(withStateMachine.name())) {
90+
updateCache(metaAnnotation.annotationType().getName() + withStateMachine.name(),
91+
new CacheEntry(handler, annotation, metaAnnotation));
92+
}
93+
if (StringUtils.hasText(withStateMachine.id())) {
94+
updateCache(metaAnnotation.annotationType().getName() + withStateMachine.id(),
95+
new CacheEntry(handler, annotation, metaAnnotation));
9396
}
94-
list.add(new CacheEntry(handler, annotation, metaAnnotation));
9597
}
9698
}
9799

@@ -103,6 +105,9 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
103105
}
104106

105107
public void callOnStateChanged(String stateMachineId, StateContext<S, E> stateContext) {
108+
if (!StringUtils.hasText(stateMachineId)) {
109+
return;
110+
}
106111
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
107112
String cacheKey = OnStateChanged.class.getName() + stateMachineId;
108113
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -120,6 +125,9 @@ public void callOnStateChanged(String stateMachineId, StateContext<S, E> stateCo
120125
}
121126

122127
public void callOnStateEntry(String stateMachineId, StateContext<S, E> stateContext) {
128+
if (!StringUtils.hasText(stateMachineId)) {
129+
return;
130+
}
123131
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
124132
String cacheKey = OnStateEntry.class.getName() + stateMachineId;
125133
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -137,6 +145,9 @@ public void callOnStateEntry(String stateMachineId, StateContext<S, E> stateCont
137145
}
138146

139147
public void callOnStateExit(String stateMachineId, StateContext<S, E> stateContext) {
148+
if (!StringUtils.hasText(stateMachineId)) {
149+
return;
150+
}
140151
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
141152
String cacheKey = OnStateExit.class.getName() + stateMachineId;
142153
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -154,6 +165,9 @@ public void callOnStateExit(String stateMachineId, StateContext<S, E> stateConte
154165
}
155166

156167
public void callOnEventNotAccepted(String stateMachineId, StateContext<S, E> stateContext) {
168+
if (!StringUtils.hasText(stateMachineId)) {
169+
return;
170+
}
157171
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
158172
String cacheKey = OnEventNotAccepted.class.getName() + stateMachineId;
159173
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -175,6 +189,9 @@ public void callOnEventNotAccepted(String stateMachineId, StateContext<S, E> sta
175189

176190

177191
public void callOnTransitionStart(String stateMachineId, StateContext<S, E> stateContext) {
192+
if (!StringUtils.hasText(stateMachineId)) {
193+
return;
194+
}
178195
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
179196
String cacheKey = OnTransitionStart.class.getName() + stateMachineId;
180197
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -192,6 +209,9 @@ public void callOnTransitionStart(String stateMachineId, StateContext<S, E> stat
192209
}
193210

194211
public void callOnTransition(String stateMachineId, StateContext<S, E> stateContext) {
212+
if (!StringUtils.hasText(stateMachineId)) {
213+
return;
214+
}
195215
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
196216
String cacheKey = OnTransition.class.getName() + stateMachineId;
197217
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -209,6 +229,9 @@ public void callOnTransition(String stateMachineId, StateContext<S, E> stateCont
209229
}
210230

211231
public void callOnTransitionEnd(String stateMachineId, StateContext<S, E> stateContext) {
232+
if (!StringUtils.hasText(stateMachineId)) {
233+
return;
234+
}
212235
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
213236
String cacheKey = OnTransitionEnd.class.getName() + stateMachineId;
214237
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -226,6 +249,9 @@ public void callOnTransitionEnd(String stateMachineId, StateContext<S, E> stateC
226249
}
227250

228251
public void callOnStateMachineStart(String stateMachineId, StateContext<S, E> stateContext) {
252+
if (!StringUtils.hasText(stateMachineId)) {
253+
return;
254+
}
229255
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
230256
String cacheKey = OnStateMachineStart.class.getName() + stateMachineId;
231257
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -239,6 +265,9 @@ public void callOnStateMachineStart(String stateMachineId, StateContext<S, E> st
239265
}
240266

241267
public void callOnStateMachineStop(String stateMachineId, StateContext<S, E> stateContext) {
268+
if (!StringUtils.hasText(stateMachineId)) {
269+
return;
270+
}
242271
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
243272
String cacheKey = OnStateMachineStop.class.getName() + stateMachineId;
244273
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -252,6 +281,9 @@ public void callOnStateMachineStop(String stateMachineId, StateContext<S, E> sta
252281
}
253282

254283
public void callOnStateMachineError(String stateMachineId, StateContext<S, E> stateContext) {
284+
if (!StringUtils.hasText(stateMachineId)) {
285+
return;
286+
}
255287
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
256288
String cacheKey = OnStateMachineError.class.getName() + stateMachineId;
257289
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -265,6 +297,9 @@ public void callOnStateMachineError(String stateMachineId, StateContext<S, E> st
265297
}
266298

267299
public void callOnExtendedStateChanged(String stateMachineId, Object key, Object value, StateContext<S, E> stateContext) {
300+
if (!StringUtils.hasText(stateMachineId)) {
301+
return;
302+
}
268303
List<StateMachineHandler<? extends Annotation, S, E>> handlersList = new ArrayList<StateMachineHandler<? extends Annotation, S, E>>();
269304
String cacheKey = OnExtendedStateChanged.class.getName() + stateMachineId;
270305
List<CacheEntry> list = getCacheEntries(cacheKey);
@@ -279,6 +314,15 @@ public void callOnExtendedStateChanged(String stateMachineId, Object key, Object
279314
getStateMachineHandlerResults(handlersList, stateContext);
280315
}
281316

317+
private void updateCache(String key, CacheEntry cacheEntry) {
318+
List<CacheEntry> list = cache.get(key);
319+
if (list == null) {
320+
list = new ArrayList<>();
321+
cache.put(key, list);
322+
}
323+
list.add(cacheEntry);
324+
}
325+
282326
private synchronized List<CacheEntry> getCacheEntries(String cacheKey) {
283327
if (stateMachineHandlerApplicationListener != null) {
284328
Long l = stateMachineHandlerApplicationListener.getLastRefreshTime();

0 commit comments

Comments
 (0)