From 1e60b7abfa9d83faa1430d19357b891b2e7312a2 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sun, 9 Jul 2017 08:41:30 +0100 Subject: [PATCH] Add support for multiple end states with javaconfig - Add missing support for defining more than one end states and as it's just missing from javaconfig. - Backport #368 - Relates #307 --- .../configurers/DefaultStateConfigurer.java | 8 +-- .../config/configurers/StateConfigurer.java | 5 +- .../config/ConfigurationTests.java | 48 +++++++++++++- .../statemachine/state/EndStateTests.java | 62 ++++++++++++++++++- 4 files changed, 115 insertions(+), 8 deletions(-) diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultStateConfigurer.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultStateConfigurer.java index b9eb883d..133b6443 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultStateConfigurer.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/DefaultStateConfigurer.java @@ -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. @@ -51,7 +51,7 @@ public class DefaultStateConfigurer private final Map> incomplete = new HashMap>(); private S initialState; private Action initialAction; - private S end; + private final Collection ends = new ArrayList<>(); private S history; private History historyType; private final Collection choices = new ArrayList(); @@ -75,7 +75,7 @@ public class DefaultStateConfigurer s.setInitial(true); s.setInitialAction(initialAction); } - if (s.getState() == end) { + if (ends.contains(s.getState())) { s.setEnd(true); } if (choices.contains(s.getState())) { @@ -125,7 +125,7 @@ public class DefaultStateConfigurer @Override public StateConfigurer end(S end) { - this.end = end; + this.ends.add(end); state(end); return this; } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/StateConfigurer.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/StateConfigurer.java index 1f58ea62..4571f850 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/StateConfigurer.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configurers/StateConfigurer.java @@ -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. @@ -223,7 +223,8 @@ public interface StateConfigurer extends StateConfigurer states(Set states); /** - * Specify a state {@code S} to be end state. + * Specify a state {@code S} to be end state. This method + * can be called for each state to be marked as end state. * * @param end the end state * @return configurer for chaining diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java index 19687ac1..199304d4 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/ConfigurationTests.java @@ -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. @@ -49,6 +49,8 @@ import org.springframework.statemachine.config.builders.StateMachineConfiguratio import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; import org.springframework.statemachine.listener.StateMachineListenerAdapter; +import org.springframework.statemachine.state.PseudoStateKind; +import org.springframework.statemachine.state.State; /** * Tests for state machine configuration. @@ -290,6 +292,28 @@ public class ConfigurationTests extends AbstractStateMachineTests { assertThat(stateMachine.getId(), is("testid2")); } + @SuppressWarnings("unchecked") + @Test + public void testMultipleEndStates() { + context.register(Config20.class); + context.refresh(); + assertTrue(context.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE)); + ObjectStateMachine machine = + context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class); + + Collection> states = machine.getStates(); + for (State s : states) { + if (s.getId().equals("S3")) { + assertThat(s.getPseudoState(), notNullValue()); + assertThat(s.getPseudoState().getKind(), is(PseudoStateKind.END)); + } + if (s.getId().equals("S2")) { + assertThat(s.getPseudoState(), notNullValue()); + assertThat(s.getPseudoState().getKind(), is(PseudoStateKind.END)); + } + } + } + @Configuration @EnableStateMachine public static class Config1 extends EnumStateMachineConfigurerAdapter { @@ -872,4 +896,26 @@ public class ConfigurationTests extends AbstractStateMachineTests { } } + @Configuration + @EnableStateMachine + public static class Config20 extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("S1") + .end("S2") + .end("S3"); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source("S1") + .target("S2") + .event("E1"); + } + } } diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/EndStateTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/EndStateTests.java index f593eb9b..fa0a776e 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/EndStateTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/EndStateTests.java @@ -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. @@ -133,6 +133,38 @@ public class EndStateTests extends AbstractStateMachineTests { context.refresh(); } + @Test + public void testEndStateCompletesMultipleEndStates1() { + context.register(Config7.class); + context.refresh(); + assertTrue(context.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE)); + @SuppressWarnings("unchecked") + ObjectStateMachine machine = + context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class); + machine.start(); + assertThat(machine, notNullValue()); + assertThat(machine.isComplete(), is(false)); + machine.sendEvent(TestEvents.E1); + assertThat(machine.isComplete(), is(true)); + assertThat(machine.getState().getIds(), contains(TestStates.S1)); + } + + @Test + public void testEndStateCompletesMultipleEndStates2() { + context.register(Config7.class); + context.refresh(); + assertTrue(context.containsBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE)); + @SuppressWarnings("unchecked") + ObjectStateMachine machine = + context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, ObjectStateMachine.class); + machine.start(); + assertThat(machine, notNullValue()); + assertThat(machine.isComplete(), is(false)); + machine.sendEvent(TestEvents.E2); + assertThat(machine.isComplete(), is(true)); + assertThat(machine.getState().getIds(), contains(TestStates.S2)); + } + @Configuration @EnableStateMachine static class Config1 extends EnumStateMachineConfigurerAdapter { @@ -436,4 +468,32 @@ public class EndStateTests extends AbstractStateMachineTests { .last("SF"); } } + + @Configuration + @EnableStateMachine + static class Config7 extends EnumStateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(TestStates.SI) + .end(TestStates.S1) + .end(TestStates.S2); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TestStates.SI) + .target(TestStates.S1) + .event(TestEvents.E1) + .and() + .withExternal() + .source(TestStates.SI) + .target(TestStates.S2) + .event(TestEvents.E2); + } + } }