diff --git a/spring-statemachine-build-tests/src/test/java/org/springframework/statemachine/buildtests/ForkJoinEntryExitTests.java b/spring-statemachine-build-tests/src/test/java/org/springframework/statemachine/buildtests/ForkJoinEntryExitTests.java new file mode 100644 index 00000000..3c5d8591 --- /dev/null +++ b/spring-statemachine-build-tests/src/test/java/org/springframework/statemachine/buildtests/ForkJoinEntryExitTests.java @@ -0,0 +1,73 @@ +/* + * 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.buildtests; + +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.StateMachine; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineModelConfigurer; +import org.springframework.statemachine.config.model.StateMachineModelFactory; +import org.springframework.statemachine.test.StateMachineTestPlan; +import org.springframework.statemachine.test.StateMachineTestPlanBuilder; +import org.springframework.statemachine.uml.UmlStateMachineModelFactory; + +public class ForkJoinEntryExitTests extends AbstractBuildTests { + + @Test + @SuppressWarnings("unchecked") + public void testForkEntrys() throws Exception { + context.register(Config1.class); + context.refresh(); + StateMachine stateMachine = context.getBean(StateMachine.class); + + StateMachineTestPlan plan = + StateMachineTestPlanBuilder.builder() + .stateMachine(stateMachine) + .step().expectState("S1").and() + .step() + .sendEvent("E1") + .expectStateEntered(3) + .expectStates("S2", "S210", "S220").and() + .build(); + plan.test(); + } + + @Configuration + @EnableStateMachine + public static class Config1 extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineModelConfigurer model) throws Exception { + model + .withModel() + .factory(modelFactory()); + } + + @Bean + public StateMachineModelFactory modelFactory() { + return new UmlStateMachineModelFactory("classpath:org/springframework/statemachine/buildtests/forkjoin-entryexit.uml"); + } + } + + @Override + protected AnnotationConfigApplicationContext buildContext() { + return new AnnotationConfigApplicationContext(); + } +} diff --git a/spring-statemachine-build-tests/src/test/resources/org/springframework/statemachine/buildtests/forkjoin-entryexit.di b/spring-statemachine-build-tests/src/test/resources/org/springframework/statemachine/buildtests/forkjoin-entryexit.di new file mode 100644 index 00000000..bf9abab3 --- /dev/null +++ b/spring-statemachine-build-tests/src/test/resources/org/springframework/statemachine/buildtests/forkjoin-entryexit.di @@ -0,0 +1,2 @@ + + diff --git a/spring-statemachine-build-tests/src/test/resources/org/springframework/statemachine/buildtests/forkjoin-entryexit.notation b/spring-statemachine-build-tests/src/test/resources/org/springframework/statemachine/buildtests/forkjoin-entryexit.notation new file mode 100644 index 00000000..2b9b27f2 --- /dev/null +++ b/spring-statemachine-build-tests/src/test/resources/org/springframework/statemachine/buildtests/forkjoin-entryexit.notation @@ -0,0 +1,369 @@ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-statemachine-build-tests/src/test/resources/org/springframework/statemachine/buildtests/forkjoin-entryexit.uml b/spring-statemachine-build-tests/src/test/resources/org/springframework/statemachine/buildtests/forkjoin-entryexit.uml new file mode 100644 index 00000000..d256483a --- /dev/null +++ b/spring-statemachine-build-tests/src/test/resources/org/springframework/statemachine/buildtests/forkjoin-entryexit.uml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/state/RegionState.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/state/RegionState.java index 6d6dcc27..f6438ea5 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/state/RegionState.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/state/RegionState.java @@ -17,11 +17,13 @@ package org.springframework.statemachine.state; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import org.springframework.messaging.Message; import org.springframework.statemachine.StateContext; import org.springframework.statemachine.action.Action; import org.springframework.statemachine.region.Region; +import org.springframework.statemachine.support.StateMachineUtils; /** * A {@link State} implementation where states are wrapped in a regions.. @@ -144,6 +146,7 @@ public class RegionState extends AbstractState { @Override public void entry(StateContext context) { + System.out.println("XXXXXX " + context); if (join != null) { join.entry(context); } @@ -156,7 +159,19 @@ public class RegionState extends AbstractState { if (getPseudoState() != null && getPseudoState().getKind() == PseudoStateKind.INITIAL) { for (Region region : getRegions()) { - region.start(); + boolean start = true; + PseudoState ps = context.getTransition().getTarget().getPseudoState(); + if (ps != null && ps.getKind() == PseudoStateKind.FORK) { + List> forks = ((ForkPseudoState)ps).getForks(); + if (StateMachineUtils.containsAtleastOne(region.getStates(), forks)) { + // it looks like fork will take directly into a state so don't start + // as we want to bypass initial entry logic. + start = false; + } + } + if (start) { + region.start(); + } } } else { for (Region region : getRegions()) { diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java index 5a4f1991..7b6196eb 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java @@ -33,8 +33,8 @@ import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.support.MessageBuilder; import org.springframework.statemachine.ExtendedState; import org.springframework.statemachine.ExtendedState.ExtendedStateChangeListener; -import org.springframework.statemachine.StateContext.Stage; import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.StateContext.Stage; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.StateMachineContext; import org.springframework.statemachine.access.StateMachineAccess; diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/ForkStateTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/ForkStateTests.java index 8694f654..75b0bc60 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/ForkStateTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/state/ForkStateTests.java @@ -62,20 +62,18 @@ public class ForkStateTests extends AbstractStateMachineTests { assertThat(machine, notNullValue()); machine.start(); - listener.reset(4); + listener.reset(2); machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).setHeader("foo", "bar").build()); assertThat(listener.stateChangedLatch.await(2, TimeUnit.SECONDS), is(true)); - assertThat(listener.stateChangedCount, is(4)); + assertThat(listener.stateChangedCount, is(2)); assertThat(machine.getState().getIds(), containsInAnyOrder(TestStates.S2, TestStates.S21, TestStates.S31)); - assertThat(s20EntryAction.stateContexts.size(), is(1)); + assertThat(s20EntryAction.stateContexts.size(), is(0)); assertThat(s21EntryAction.stateContexts.size(), is(1)); - assertThat(s30EntryAction.stateContexts.size(), is(1)); + assertThat(s30EntryAction.stateContexts.size(), is(0)); assertThat(s31EntryAction.stateContexts.size(), is(1)); - assertThat((String)s20EntryAction.stateContexts.get(0).getMessageHeader("foo"), nullValue()); assertThat((String)s21EntryAction.stateContexts.get(0).getMessageHeader("foo"), is("bar")); - assertThat((String)s30EntryAction.stateContexts.get(0).getMessageHeader("foo"), nullValue()); assertThat((String)s31EntryAction.stateContexts.get(0).getMessageHeader("foo"), is("bar")); } @@ -128,19 +126,18 @@ public class ForkStateTests extends AbstractStateMachineTests { assertThat(machine, notNullValue()); machine.start(); - listener.reset(3); + listener.reset(2); machine.sendEvent(MessageBuilder.withPayload(TestEvents.E1).setHeader("foo", "bar").build()); assertThat(listener.stateChangedLatch.await(2, TimeUnit.SECONDS), is(true)); - assertThat(listener.stateChangedCount, is(3)); + assertThat(listener.stateChangedCount, is(2)); assertThat(machine.getState().getIds(), containsInAnyOrder(TestStates.S2, TestStates.S20, TestStates.S31)); assertThat(s20EntryAction.stateContexts.size(), is(1)); assertThat(s21EntryAction.stateContexts.size(), is(0)); - assertThat(s30EntryAction.stateContexts.size(), is(1)); + assertThat(s30EntryAction.stateContexts.size(), is(0)); assertThat(s31EntryAction.stateContexts.size(), is(1)); assertThat((String)s20EntryAction.stateContexts.get(0).getMessageHeader("foo"), nullValue()); - assertThat((String)s30EntryAction.stateContexts.get(0).getMessageHeader("foo"), nullValue()); assertThat((String)s31EntryAction.stateContexts.get(0).getMessageHeader("foo"), is("bar")); }