Should not define initial state as state
- Tweak DefaultStateConfigurer so that we don't need to define initial state as additional state. Also fixed some other issue which caused a bit of a mess when i.e multiple states were introduces twice. - Fixes #29
This commit is contained in:
@@ -61,14 +61,26 @@ public class StateData<S, E> {
|
||||
public Collection<E> getDeferred() {
|
||||
return deferred;
|
||||
}
|
||||
|
||||
public void setDeferred(Collection<E> deferred) {
|
||||
this.deferred = deferred;
|
||||
}
|
||||
|
||||
public Collection<? extends Action<S, E>> getEntryActions() {
|
||||
return entryActions;
|
||||
}
|
||||
|
||||
public void setEntryActions(Collection<? extends Action<S, E>> entryActions) {
|
||||
this.entryActions = entryActions;
|
||||
}
|
||||
|
||||
public Collection<? extends Action<S, E>> getExitActions() {
|
||||
return exitActions;
|
||||
}
|
||||
|
||||
public void setExitActions(Collection<? extends Action<S, E>> exitActions) {
|
||||
this.exitActions = exitActions;
|
||||
}
|
||||
|
||||
public Object getParent() {
|
||||
return parent;
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.statemachine.config.configurers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -45,7 +47,7 @@ public class DefaultStateConfigurer<S, E>
|
||||
|
||||
private final Object region = UUID.randomUUID().toString();
|
||||
|
||||
private final Collection<StateData<S, E>> incomplete = new ArrayList<StateData<S, E>>();
|
||||
private final Map<S, StateData<S, E>> incomplete = new HashMap<S, StateData<S, E>>();
|
||||
|
||||
private S initialState;
|
||||
|
||||
@@ -68,7 +70,7 @@ public class DefaultStateConfigurer<S, E>
|
||||
// before passing state datas to builder, update structure
|
||||
// for missing parent, initial and end state infos.
|
||||
Collection<StateData<S, E>> stateDatas = new ArrayList<StateData<S, E>>();
|
||||
for (StateData<S, E> s : incomplete) {
|
||||
for (StateData<S, E> s : incomplete.values()) {
|
||||
s.setParent(parent);
|
||||
stateDatas.add(s);
|
||||
if (s.getState() == initialState) {
|
||||
@@ -99,6 +101,7 @@ public class DefaultStateConfigurer<S, E>
|
||||
@Override
|
||||
public StateConfigurer<S, E> initial(S initial) {
|
||||
this.initialState = initial;
|
||||
state(initial);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -195,7 +198,26 @@ public class DefaultStateConfigurer<S, E>
|
||||
|
||||
private void addIncomplete(Object parent, S state, Collection<E> deferred,
|
||||
Collection<? extends Action<S, E>> entryActions, Collection<? extends Action<S, E>> exitActions) {
|
||||
incomplete.add(new StateData<S, E>(parent, region, state, deferred, entryActions, exitActions));
|
||||
StateData<S, E> stateData = incomplete.get(state);
|
||||
if (stateData == null) {
|
||||
stateData = new StateData<S, E>(parent, region, state, deferred, entryActions, exitActions);
|
||||
incomplete.put(state, stateData);
|
||||
}
|
||||
if (stateData.getParent() == null) {
|
||||
stateData.setParent(parent);
|
||||
}
|
||||
if (stateData.getRegion() == null) {
|
||||
stateData.setRegion(region);
|
||||
}
|
||||
if (stateData.getDeferred() == null) {
|
||||
stateData.setDeferred(deferred);
|
||||
}
|
||||
if (stateData.getEntryActions() == null) {
|
||||
stateData.setEntryActions(entryActions);
|
||||
}
|
||||
if (stateData.getExitActions() == null) {
|
||||
stateData.setExitActions(exitActions);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.config.configurers;
|
||||
|
||||
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.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests.TestEntryAction;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests.TestEvents;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests.TestExitAction;
|
||||
import org.springframework.statemachine.AbstractStateMachineTests.TestStates;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.StateData;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateBuilder;
|
||||
|
||||
public class DefaultStateConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testInitialWithoutState() throws Exception {
|
||||
DefaultStateConfigurer<TestStates, TestEvents> configurer = new DefaultStateConfigurer<TestStates, TestEvents>();
|
||||
TestStateMachineStateBuilder builder = new TestStateMachineStateBuilder();
|
||||
configurer.initial(TestStates.SI);
|
||||
configurer.configure(builder);
|
||||
assertThat(builder.data, notNullValue());
|
||||
assertThat(builder.data.size(), is(1));
|
||||
assertThat(builder.data.iterator().next().getState(), is(TestStates.SI));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitialWithState() throws Exception {
|
||||
DefaultStateConfigurer<TestStates, TestEvents> configurer = new DefaultStateConfigurer<TestStates, TestEvents>();
|
||||
TestStateMachineStateBuilder builder = new TestStateMachineStateBuilder();
|
||||
configurer.initial(TestStates.SI);
|
||||
configurer.state(TestStates.SI);
|
||||
configurer.configure(builder);
|
||||
assertThat(builder.data, notNullValue());
|
||||
assertThat(builder.data.size(), is(1));
|
||||
assertThat(builder.data.iterator().next().getState(), is(TestStates.SI));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameStateShouldResultOneState() throws Exception {
|
||||
DefaultStateConfigurer<TestStates, TestEvents> configurer = new DefaultStateConfigurer<TestStates, TestEvents>();
|
||||
TestStateMachineStateBuilder builder = new TestStateMachineStateBuilder();
|
||||
configurer.state(TestStates.SI);
|
||||
configurer.state(TestStates.SI);
|
||||
configurer.configure(builder);
|
||||
assertThat(builder.data, notNullValue());
|
||||
assertThat(builder.data.size(), is(1));
|
||||
assertThat(builder.data.iterator().next().getState(), is(TestStates.SI));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParentSet() throws Exception {
|
||||
DefaultStateConfigurer<TestStates, TestEvents> configurer = new DefaultStateConfigurer<TestStates, TestEvents>();
|
||||
TestStateMachineStateBuilder builder = new TestStateMachineStateBuilder();
|
||||
configurer.parent(TestStates.SI);
|
||||
configurer.state(TestStates.S1);
|
||||
configurer.configure(builder);
|
||||
assertThat(builder.data, notNullValue());
|
||||
assertThat(builder.data.size(), is(1));
|
||||
assertThat(builder.data.iterator().next().getState(), is(TestStates.S1));
|
||||
assertThat((TestStates)builder.data.iterator().next().getParent(), is(TestStates.SI));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionsInitialFirst() throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Action<TestStates, TestEvents>> exitActions = Arrays.asList(testExitAction());
|
||||
|
||||
DefaultStateConfigurer<TestStates, TestEvents> configurer = new DefaultStateConfigurer<TestStates, TestEvents>();
|
||||
TestStateMachineStateBuilder builder = new TestStateMachineStateBuilder();
|
||||
configurer.initial(TestStates.S1);
|
||||
configurer.state(TestStates.S1, null, exitActions);
|
||||
configurer.configure(builder);
|
||||
assertThat(builder.data, notNullValue());
|
||||
assertThat(builder.data.size(), is(1));
|
||||
|
||||
assertThat(builder.data.iterator().next().getState(), is(TestStates.S1));
|
||||
assertThat(builder.data.iterator().next().getEntryActions(), nullValue());
|
||||
assertThat(builder.data.iterator().next().getExitActions(), notNullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionsJustState() throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Action<TestStates, TestEvents>> entryActions = Arrays.asList(testEntryAction());
|
||||
|
||||
DefaultStateConfigurer<TestStates, TestEvents> configurer = new DefaultStateConfigurer<TestStates, TestEvents>();
|
||||
TestStateMachineStateBuilder builder = new TestStateMachineStateBuilder();
|
||||
configurer.state(TestStates.S2, entryActions, null);
|
||||
configurer.configure(builder);
|
||||
assertThat(builder.data, notNullValue());
|
||||
assertThat(builder.data.size(), is(1));
|
||||
|
||||
assertThat(builder.data.iterator().next().getState(), is(TestStates.S2));
|
||||
assertThat(builder.data.iterator().next().getExitActions(), nullValue());
|
||||
assertThat(builder.data.iterator().next().getEntryActions(), notNullValue());
|
||||
}
|
||||
|
||||
private static class TestStateMachineStateBuilder extends StateMachineStateBuilder<TestStates, TestEvents> {
|
||||
|
||||
Collection<StateData<TestStates, TestEvents>> data;
|
||||
|
||||
@Override
|
||||
public void addStateData(Collection<StateData<TestStates, TestEvents>> stateDatas) {
|
||||
this.data = stateDatas;
|
||||
}
|
||||
}
|
||||
|
||||
private Action<TestStates, TestEvents> testEntryAction() {
|
||||
return new TestEntryAction();
|
||||
}
|
||||
|
||||
private Action<TestStates, TestEvents> testExitAction() {
|
||||
return new TestExitAction();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -58,6 +58,20 @@ public class InitialStateTests extends AbstractStateMachineTests {
|
||||
context.refresh();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Test
|
||||
public void testInitialNoNeedAsState() throws Exception {
|
||||
context.register(BaseConfig.class, Config3.class);
|
||||
context.refresh();
|
||||
assertTrue(context.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE));
|
||||
EnumStateMachine<TestStates,TestEvents> machine =
|
||||
context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, EnumStateMachine.class);
|
||||
machine.start();
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.SI));
|
||||
machine.sendEvent(TestEvents.E1);
|
||||
assertThat(machine.getState().getIds(), contains(TestStates.S1));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public static class Config1 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
|
||||
@@ -111,6 +125,29 @@ public class InitialStateTests extends AbstractStateMachineTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public static class Config3 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial(TestStates.SI)
|
||||
.state(TestStates.S1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(TestStates.SI)
|
||||
.target(TestStates.S1)
|
||||
.event(TestEvents.E1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotationConfigApplicationContext buildContext() {
|
||||
return new AnnotationConfigApplicationContext();
|
||||
|
||||
Reference in New Issue
Block a user