Allow user to use machine id

- change original id to uuid.
- This new id is now for user disposal.
- Currently only meant for a top-level machine.
- Can be set via annotation config, model classes or via
  new StateMachineFactory.getStateMachine(String).
- Is persisted with DefaultStateMachinePersister and
  StateMachineContext.
- Related new tests in ConfigurationTests and StateMachinePersistTests3.
- Fixes #186
This commit is contained in:
Janne Valkealahti
2016-03-24 07:54:36 +00:00
parent a82ff5b936
commit 1bf65760d5
20 changed files with 375 additions and 31 deletions

View File

@@ -28,6 +28,13 @@ import java.util.Map;
*/
public interface StateMachineContext<S, E> {
/**
* Gets the machine id.
*
* @return the machine id
*/
String getId();
/**
* Gets the child contexts if any.
*

View File

@@ -112,9 +112,14 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
this.beanName = name;
}
@SuppressWarnings("unchecked")
@Override
public StateMachine<S, E> getStateMachine() {
return getStateMachine(null);
}
@SuppressWarnings("unchecked")
@Override
public StateMachine<S, E> getStateMachine(String machineId) {
if (stateMachineModel.getConfigurationData().isVerifierEnabled()) {
StateMachineModelVerifier<S, E> verifier = stateMachineModel.getConfigurationData().getVerifier();
if (verifier == null) {
@@ -173,7 +178,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
for (Collection<StateData<S, E>> regionStateDatas : regionsStateDatas) {
machine = buildMachine(machineMap, stateMap, regionStateDatas, transitionsData, resolveBeanFactory(),
contextEvents, defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(),
resolveTaskScheduler());
resolveTaskScheduler(), machineId);
regionStack.push(new MachineStackItem<S, E>(machine));
}
@@ -192,14 +197,16 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
Collection<State<S, E>> states = new ArrayList<State<S, E>>();
states.add(rstate);
Transition<S, E> initialTransition = new InitialTransition<S, E>(rstate);
StateMachine<S, E> m = buildStateMachineInternal(states, new ArrayList<Transition<S, E>>(), rstate,
initialTransition, null, defaultExtendedState, null, contextEvents, resolveBeanFactory(),
resolveTaskExecutor(), resolveTaskScheduler(), beanName);
StateMachine<S, E> m = buildStateMachineInternal(states, new ArrayList<Transition<S, E>>(), rstate, initialTransition,
null, defaultExtendedState, null, contextEvents, resolveBeanFactory(), resolveTaskExecutor(),
resolveTaskScheduler(), beanName,
machineId != null ? machineId : stateMachineModel.getConfigurationData().getMachineId());
machine = m;
}
} else {
machine = buildMachine(machineMap, stateMap, stateDatas, transitionsData, resolveBeanFactory(),
contextEvents, defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(), resolveTaskScheduler());
machine = buildMachine(machineMap, stateMap, stateDatas, transitionsData, resolveBeanFactory(), contextEvents,
defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(), resolveTaskScheduler(),
machineId);
if (peek.isInitial() || (!peek.isInitial() && !machineMap.containsKey(peek.getParent()))) {
machineMap.put(peek.getParent(), machine);
}
@@ -395,7 +402,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
Collection<StateData<S, E>> stateDatas, Collection<TransitionData<S, E>> transitionsData,
BeanFactory beanFactory, Boolean contextEvents, DefaultExtendedState defaultExtendedState,
TransitionsData<S, E> stateMachineTransitions, TaskExecutor taskExecutor,
TaskScheduler taskScheduler) {
TaskScheduler taskScheduler, String machineId) {
State<S, E> state = null;
State<S, E> initialState = null;
PseudoState<S, E> historyState = null;
@@ -579,7 +586,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
Transition<S, E> initialTransition = new InitialTransition<S, E>(initialState, initialAction);
StateMachine<S, E> machine = buildStateMachineInternal(states, transitions, initialState, initialTransition,
null, defaultExtendedState, historyState, contextEvents, beanFactory, taskExecutor, taskScheduler,
beanName);
beanName, machineId != null ? machineId : stateMachineModel.getConfigurationData().getMachineId());
return machine;
}
@@ -587,7 +594,7 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
Collection<Transition<S, E>> transitions, State<S, E> initialState, Transition<S, E> initialTransition,
Message<E> initialEvent, ExtendedState extendedState, PseudoState<S, E> historyState,
Boolean contextEventsEnabled, BeanFactory beanFactory, TaskExecutor taskExecutor,
TaskScheduler taskScheduler, String beanName);
TaskScheduler taskScheduler, String beanName, String machineId);
protected abstract State<S, E> buildStateInternal(S id, Collection<E> deferred, Collection<? extends Action<S, E>> entryActions, Collection<? extends Action<S, E>> exitActions,
PseudoState<S, E> pseudoState);

View File

@@ -59,9 +59,10 @@ public class ObjectStateMachineFactory<S, E> extends AbstractStateMachineFactory
Collection<Transition<S, E>> transitions, State<S, E> initialState, Transition<S, E> initialTransition,
Message<E> initialEvent, ExtendedState extendedState, PseudoState<S, E> historyState,
Boolean contextEventsEnabled, BeanFactory beanFactory, TaskExecutor taskExecutor,
TaskScheduler taskScheduler, String beanName) {
TaskScheduler taskScheduler, String beanName, String machineId) {
ObjectStateMachine<S, E> machine = new ObjectStateMachine<S, E>(states, transitions, initialState, initialTransition, initialEvent,
extendedState);
machine.setId(machineId);
machine.setHistoryState(historyState);
if (contextEventsEnabled != null) {
machine.setContextEventsEnabled(contextEventsEnabled);
@@ -73,7 +74,7 @@ public class ObjectStateMachineFactory<S, E> extends AbstractStateMachineFactory
machine.setTaskExecutor(taskExecutor);
}
if (taskScheduler != null) {
machine.setTaskScheduler(taskScheduler);;
machine.setTaskScheduler(taskScheduler);
}
if (machine instanceof BeanNameAware) {
((BeanNameAware)machine).setBeanName(beanName);

View File

@@ -19,7 +19,7 @@ import org.springframework.statemachine.StateMachine;
/**
* {@code StateMachineFactory} is a strategy interface building {@link StateMachine}s.
*
*
* @author Janne Valkealahti
*
* @param <S> the type of state
@@ -29,9 +29,17 @@ public interface StateMachineFactory<S, E> {
/**
* Build a new {@link StateMachine} instance.
*
*
* @return a new state machine instance.
*/
StateMachine<S, E> getStateMachine();
/**
* Build a new {@link StateMachine} instance
* with a given machine id.
*
* @param machineId the machine id
* @return a new state machine instance.
*/
StateMachine<S, E> getStateMachine(String machineId);
}

View File

@@ -52,6 +52,7 @@ public class StateMachineConfigurationBuilder<S, E>
extends AbstractConfiguredAnnotationBuilder<ConfigurationData<S, E>, StateMachineConfigurationConfigurer<S, E>, StateMachineConfigurationBuilder<S, E>>
implements StateMachineConfigurationConfigurer<S, E> {
private String machineId;
private BeanFactory beanFactory;
private TaskExecutor taskExecutor;
private TaskScheduler taskScheculer;
@@ -117,7 +118,16 @@ public class StateMachineConfigurationBuilder<S, E>
protected ConfigurationData<S, E> performBuild() throws Exception {
return new ConfigurationData<S, E>(beanFactory, taskExecutor, taskScheculer, autoStart, ensemble, listeners,
securityEnabled, transitionSecurityAccessDecisionManager, eventSecurityAccessDecisionManager, eventSecurityRule,
transitionSecurityRule, verifierEnabled, verifier);
transitionSecurityRule, verifierEnabled, verifier, machineId);
}
/**
* Sets the machine id.
*
* @param machineId the new machine id
*/
public void setMachineId(String machineId) {
this.machineId = machineId;
}
/**

View File

@@ -18,6 +18,7 @@ package org.springframework.statemachine.config.configurers;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder;
import org.springframework.statemachine.listener.StateMachineListener;
@@ -33,6 +34,15 @@ import org.springframework.statemachine.listener.StateMachineListener;
public interface ConfigurationConfigurer<S, E> extends
AnnotationConfigurerBuilder<StateMachineConfigurationConfigurer<S, E>> {
/**
* Specify a machine identifier.
*
* @param id the machine identifier
* @return configurer for chaining
* @see StateMachine#getId()
*/
ConfigurationConfigurer<S, E> machineId(String id);
/**
* Specify a {@link BeanFactory}.
*

View File

@@ -39,6 +39,7 @@ public class DefaultConfigurationConfigurer<S, E>
extends AnnotationConfigurerAdapter<ConfigurationData<S, E>, StateMachineConfigurationConfigurer<S, E>, StateMachineConfigurationBuilder<S, E>>
implements ConfigurationConfigurer<S, E> {
private String machineId;
private BeanFactory beanFactory;
private TaskExecutor taskExecutor;
private TaskScheduler taskScheculer;
@@ -47,6 +48,7 @@ public class DefaultConfigurationConfigurer<S, E>
@Override
public void configure(StateMachineConfigurationBuilder<S, E> builder) throws Exception {
builder.setMachineId(machineId);
builder.setBeanFactory(beanFactory);
builder.setTaskExecutor(taskExecutor);
builder.setTaskScheculer(taskScheculer);
@@ -54,6 +56,12 @@ public class DefaultConfigurationConfigurer<S, E>
builder.setStateMachineListeners(listeners);
}
@Override
public ConfigurationConfigurer<S, E> machineId(String id) {
this.machineId = id;
return this;
}
@Override
public ConfigurationConfigurer<S, E> beanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;

View File

@@ -41,6 +41,7 @@ import org.springframework.statemachine.security.SecurityRule;
*/
public class ConfigurationData<S, E> {
private final String machineId;
private final BeanFactory beanFactory;
private final TaskExecutor taskExecutor;
private final TaskScheduler taskScheduler;
@@ -60,7 +61,7 @@ public class ConfigurationData<S, E> {
*/
public ConfigurationData() {
this(null, new SyncTaskExecutor(), new ConcurrentTaskScheduler(), false, null, new ArrayList<StateMachineListener<S, E>>(), false,
null, null, null, null, true, new DefaultStateMachineModelVerifier<S, E>());
null, null, null, null, true, new DefaultStateMachineModelVerifier<S, E>(), null);
}
/**
@@ -79,13 +80,14 @@ public class ConfigurationData<S, E> {
* @param transitionSecurityRule the transition security rule
* @param verifierEnabled the verifier enabled flag
* @param verifier the state machine model verifier
* @param machineId the machine id
*/
public ConfigurationData(BeanFactory beanFactory, TaskExecutor taskExecutor,
TaskScheduler taskScheduler, boolean autoStart, StateMachineEnsemble<S, E> ensemble,
List<StateMachineListener<S, E>> listeners, boolean securityEnabled,
AccessDecisionManager transitionSecurityAccessDecisionManager, AccessDecisionManager eventSecurityAccessDecisionManager,
SecurityRule eventSecurityRule, SecurityRule transitionSecurityRule, boolean verifierEnabled,
StateMachineModelVerifier<S, E> verifier) {
StateMachineModelVerifier<S, E> verifier, String machineId) {
this.beanFactory = beanFactory;
this.taskExecutor = taskExecutor;
this.taskScheduler = taskScheduler;
@@ -99,6 +101,11 @@ public class ConfigurationData<S, E> {
this.transitionSecurityRule = transitionSecurityRule;
this.verifierEnabled = verifierEnabled;
this.verifier = verifier;
this.machineId = machineId;
}
public String getMachineId() {
return machineId;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -16,6 +16,7 @@
package org.springframework.statemachine.ensemble;
import java.util.Collection;
import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -105,7 +106,7 @@ public class DistributedStateMachine<S, E> extends LifecycleObjectSupport implem
// adding state machine id to the message so that
// listeners can know from where a state change originates
return delegate.sendEvent(MessageBuilder.fromMessage(event)
.setHeader(StateMachineSystemConstants.STATEMACHINE_IDENTIFIER, delegate.getId()).build());
.setHeader(StateMachineSystemConstants.STATEMACHINE_IDENTIFIER, delegate.getUuid()).build());
}
@Override
@@ -168,6 +169,11 @@ public class DistributedStateMachine<S, E> extends LifecycleObjectSupport implem
return delegate.getStateMachineAccessor();
}
@Override
public UUID getUuid() {
return delegate.getUuid();
}
@Override
public String getId() {
return delegate.getId();
@@ -198,7 +204,7 @@ public class DistributedStateMachine<S, E> extends LifecycleObjectSupport implem
}
// only handle if state change originates from this dist machine
if (message != null
&& ObjectUtils.nullSafeEquals(delegate.getId(),
&& ObjectUtils.nullSafeEquals(delegate.getUuid(),
message.getHeaders().get(StateMachineSystemConstants.STATEMACHINE_IDENTIFIER))) {
ensemble.setState(new DefaultStateMachineContext<S, E>(transition.getTarget().getId(), message
.getPayload(), message.getHeaders(), stateMachine.getExtendedState()));
@@ -220,7 +226,7 @@ public class DistributedStateMachine<S, E> extends LifecycleObjectSupport implem
// only handle if state change originates from this dist machine
if (stateContext.getTransition() != null
&& stateContext.getTransition().getKind() == TransitionKind.INTERNAL
&& ObjectUtils.nullSafeEquals(delegate.getId(),
&& ObjectUtils.nullSafeEquals(delegate.getUuid(),
stateContext.getMessageHeader(StateMachineSystemConstants.STATEMACHINE_IDENTIFIER))) {
StateMachineContext<S, E> current = ensemble.getState();
if (current != null) {
@@ -276,7 +282,7 @@ public class DistributedStateMachine<S, E> extends LifecycleObjectSupport implem
});
}
log.info("Requesting to start delegating state machine " + delegate);
log.info("Delegating machine id " + delegate.getId());
log.info("Delegating machine id " + delegate.getUuid());
delegate.start();
}
}
@@ -292,7 +298,7 @@ public class DistributedStateMachine<S, E> extends LifecycleObjectSupport implem
@Override
public void stateChanged(StateMachineContext<S, E> context) {
// do not pass if state change was originated from this dist machine
if (!ObjectUtils.nullSafeEquals(delegate.getId(),
if (!ObjectUtils.nullSafeEquals(delegate.getUuid(),
context.getEventHeaders().get(StateMachineSystemConstants.STATEMACHINE_IDENTIFIER))) {
delegate.sendEvent(MessageBuilder.withPayload(context.getEvent())
.copyHeaders(context.getEventHeaders()).build());

View File

@@ -129,6 +129,6 @@ public abstract class AbstractStateMachinePersister<S, E, T> implements StateMac
}
}
}
return new DefaultStateMachineContext<S, E>(childs, id, null, null, extendedState, historyStates);
return new DefaultStateMachineContext<S, E>(childs, id, null, null, extendedState, historyStates, stateMachine.getId());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -16,6 +16,7 @@
package org.springframework.statemachine.region;
import java.util.Collection;
import java.util.UUID;
import org.springframework.messaging.Message;
import org.springframework.statemachine.listener.StateMachineListener;
@@ -38,6 +39,15 @@ public interface Region<S, E> {
*
* @return the region and state machine unique id
*/
UUID getUuid();
/**
* Gets the region and state machine id. This identifier
* is provided for users disposal and can be set from
* a various ways to build a machines.
*
* @return the region and state machine id
*/
String getId();
/**

View File

@@ -100,7 +100,9 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
private Boolean initialEnabled = null;
private String id = UUID.randomUUID().toString();
private UUID uuid = UUID.randomUUID();
private String id;
private volatile Message<E> forwardedInitialEvent;
@@ -490,6 +492,8 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
if (currentState != null) {
buf.append(StringUtils.collectionToCommaDelimitedString(currentState.getIds()));
}
buf.append(" / uuid=");
buf.append(uuid);
buf.append(" / id=");
buf.append(id);
return buf.toString();
@@ -507,6 +511,7 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
if (log.isDebugEnabled()) {
log.debug("Request to reset state machine: stateMachine=[" + this + "] stateMachineContext=[" + stateMachineContext + "]");
}
setId(stateMachineContext.getId());
S state = stateMachineContext.getState();
boolean stateSet = false;
// handle state reset
@@ -622,11 +627,25 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
stateMachineExecutor.addStateMachineInterceptor(interceptor);
}
@Override
public UUID getUuid() {
return uuid;
}
@Override
public String getId() {
return id;
}
/**
* Sets the machine id.
*
* @param id the new machine id
*/
public void setId(String id) {
this.id = id;
}
protected synchronized boolean acceptEvent(Message<E> message) {
if ((currentState != null && currentState.shouldDefer(message))) {
log.info("Current state " + currentState + " deferred event " + message);

View File

@@ -33,6 +33,7 @@ import org.springframework.statemachine.StateMachineContext;
*/
public class DefaultStateMachineContext<S, E> implements StateMachineContext<S, E> {
private final String id;
private final List<StateMachineContext<S, E>> childs;
private final S state;
private final Map<S, S> historyStates;
@@ -66,6 +67,21 @@ public class DefaultStateMachineContext<S, E> implements StateMachineContext<S,
this(new ArrayList<StateMachineContext<S, E>>(), state, event, eventHeaders, extendedState, historyStates);
}
/**
* Instantiates a new default state machine context.
*
* @param state the state
* @param event the event
* @param eventHeaders the event headers
* @param extendedState the extended state
* @param historyStates the history state mappings
* @param id the machine id
*/
public DefaultStateMachineContext(S state, E event, Map<String, Object> eventHeaders, ExtendedState extendedState,
Map<S, S> historyStates, String id) {
this(new ArrayList<StateMachineContext<S, E>>(), state, event, eventHeaders, extendedState, historyStates, id);
}
/**
* Instantiates a new default state machine context.
*
@@ -92,12 +108,34 @@ public class DefaultStateMachineContext<S, E> implements StateMachineContext<S,
*/
public DefaultStateMachineContext(List<StateMachineContext<S, E>> childs, S state, E event,
Map<String, Object> eventHeaders, ExtendedState extendedState, Map<S, S> historyStates) {
this(childs, state, event, eventHeaders, extendedState, historyStates, null);
}
/**
* Instantiates a new default state machine context.
*
* @param childs the child state machine contexts
* @param state the state
* @param event the event
* @param eventHeaders the event headers
* @param extendedState the extended state
* @param historyStates the history state mappings
* @param id the machine id
*/
public DefaultStateMachineContext(List<StateMachineContext<S, E>> childs, S state, E event,
Map<String, Object> eventHeaders, ExtendedState extendedState, Map<S, S> historyStates, String id) {
this.childs = childs;
this.state = state;
this.event = event;
this.eventHeaders = eventHeaders;
this.extendedState = extendedState;
this.historyStates = historyStates != null ? historyStates : new HashMap<S, S>();
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
@@ -132,7 +170,7 @@ public class DefaultStateMachineContext<S, E> implements StateMachineContext<S,
@Override
public String toString() {
return "DefaultStateMachineContext [childs=" + childs + ", state=" + state + ", historyStates=" + historyStates + ", event=" + event
+ ", eventHeaders=" + eventHeaders + ", extendedState=" + extendedState + "]";
return "DefaultStateMachineContext [id=" + id + ", childs=" + childs + ", state=" + state + ", historyStates=" + historyStates
+ ", event=" + event + ", eventHeaders=" + eventHeaders + ", extendedState=" + extendedState + "]";
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -405,7 +405,7 @@ public class DefaultStateMachineExecutor<S, E> extends LifecycleObjectSupport im
if (!map.containsKey(StateMachineSystemConstants.STATEMACHINE_IDENTIFIER)) {
// don't set sm id if it's already present because
// we want to keep the originating sm id
map.put(StateMachineSystemConstants.STATEMACHINE_IDENTIFIER, stateMachine.getId());
map.put(StateMachineSystemConstants.STATEMACHINE_IDENTIFIER, stateMachine.getUuid());
}
return new DefaultStateContext<S, E>(Stage.TRANSITION, message, new MessageHeaders(map), stateMachine.getExtendedState(), transition, stateMachine, null, null, null);
}

View File

@@ -21,6 +21,7 @@ import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import org.junit.Test;
import org.springframework.messaging.Message;
@@ -173,6 +174,11 @@ public class StateMachineAccessTests {
public void setInitialEnabled(boolean enabled) {
}
@Override
public UUID getUuid() {
return null;
}
@Override
public String getId() {
return null;

View File

@@ -242,6 +242,31 @@ public class ConfigurationTests extends AbstractStateMachineTests {
assertThat(bfFromMachine, sameInstance(Config16.beanFactory));
}
@Test
public void testMachineIdFlat() {
context.register(Config17.class);
context.refresh();
@SuppressWarnings("unchecked")
StateMachine<String, String> stateMachine = context.getBean(StateMachine.class);
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.getId(), is("testid1"));
}
@Test
public void testMachineIdViaFactory() {
context.register(Config18.class);
context.refresh();
@SuppressWarnings("unchecked")
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String,String> stateMachine = stateMachineFactory.getStateMachine();
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.getId(), is("testid1"));
stateMachine = stateMachineFactory.getStateMachine("testid2");
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.getId(), is("testid2"));
}
@Configuration
@EnableStateMachine
public static class Config1 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
@@ -731,4 +756,62 @@ public class ConfigurationTests extends AbstractStateMachineTests {
}
@Configuration
public static class Config17 {
public static BeanFactory beanFactory = new DefaultListableBeanFactory();
@Bean
StateMachine<String, String> stateMachine() throws Exception {
Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureConfiguration()
.withConfiguration()
.machineId("testid1")
.autoStartup(false)
.beanFactory(beanFactory);
builder.configureStates()
.withStates()
.initial("S1").state("S2");
builder.configureTransitions()
.withExternal()
.source("S1").target("S2").event("E1")
.and()
.withExternal()
.source("S2").target("S1").event("E2");
StateMachine<String, String> stateMachine = builder.build();
return stateMachine;
}
}
@Configuration
@EnableStateMachineFactory
public static class Config18 extends StateMachineConfigurerAdapter<String, String> {
@Override
public void configure(StateMachineConfigurationConfigurer<String, String> config) throws Exception {
config
.withConfiguration()
.machineId("testid1")
.autoStartup(true);
}
@Override
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
states
.withStates()
.initial("S1")
.state("S2");
}
@Override
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
transitions
.withExternal()
.source("S1")
.target("S2")
.event("E1");
}
}
}

View File

@@ -59,7 +59,7 @@ public class StateMachineModelTests {
ConfigurationData<String, String> configurationData = new ConfigurationData<>(beanFactory, taskExecutor, taskScheduler, autoStart,
ensemble, listeners, securityEnabled, transitionSecurityAccessDecisionManager, eventSecurityAccessDecisionManager,
eventSecurityRule, transitionSecurityRule, verifierEnabled, verifier);
eventSecurityRule, transitionSecurityRule, verifierEnabled, verifier, null);
Collection<StateData<String, String>> stateData = new ArrayList<>();
StateData<String, String> stateData1 = new StateData<String, String>(null, null, "S1", null, null, null);

View File

@@ -0,0 +1,112 @@
/*
* Copyright 2016 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.persist;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import java.util.HashMap;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.AbstractStateMachineTests;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.StateMachineContext;
import org.springframework.statemachine.StateMachinePersist;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
public class StateMachinePersistTests3 extends AbstractStateMachineTests {
@Override
protected AnnotationConfigApplicationContext buildContext() {
return new AnnotationConfigApplicationContext();
}
@Test
public void testPersistMachineId() throws Exception {
context.register(Config1.class);
context.refresh();
InMemoryStateMachinePersist1 stateMachinePersist = new InMemoryStateMachinePersist1();
StateMachinePersister<String, String, String> persister = new DefaultStateMachinePersister<>(stateMachinePersist);
@SuppressWarnings("unchecked")
StateMachineFactory<String, String> stateMachineFactory = context.getBean(StateMachineFactory.class);
StateMachine<String,String> stateMachine = stateMachineFactory.getStateMachine("testid2");
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.getId(), is("testid2"));
persister.persist(stateMachine, "xxx");
stateMachine = stateMachineFactory.getStateMachine();
assertThat(stateMachine, notNullValue());
assertThat(stateMachine.getId(), nullValue());
stateMachine = persister.restore(stateMachine, "xxx");
assertThat(stateMachine.getId(), is("testid2"));
}
@Configuration
@EnableStateMachineFactory
public static class Config1 extends StateMachineConfigurerAdapter<String, String> {
@Override
public void configure(StateMachineConfigurationConfigurer<String, String> config) throws Exception {
config
.withConfiguration()
.autoStartup(true);
}
@Override
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
states
.withStates()
.initial("S1")
.state("S2");
}
@Override
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
transitions
.withExternal()
.source("S1")
.target("S2")
.event("E1");
}
}
static class InMemoryStateMachinePersist1 implements StateMachinePersist<String, String, String> {
private final HashMap<String, StateMachineContext<String, String>> contexts = new HashMap<>();
@Override
public void write(StateMachineContext<String, String> context, String contextOjb) throws Exception {
contexts.put(contextOjb, context);
}
@Override
public StateMachineContext<String, String> read(String contextOjb) throws Exception {
return contexts.get(contextOjb);
}
}
}

View File

@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.junit.Test;
import org.springframework.expression.ExpressionParser;
@@ -209,6 +210,11 @@ public class StateContextExpressionMethodsTests {
return null;
}
@Override
public UUID getUuid() {
return null;
}
@Override
public String getId() {
return null;

View File

@@ -26,6 +26,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -756,6 +757,11 @@ public class ZookeeperStateMachineEnsembleTests extends AbstractZookeeperTests {
return null;
}
@Override
public UUID getUuid() {
return null;
}
@Override
public String getId() {
return null;