diff --git a/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/StateMachineBuilder.java b/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/StateMachineBuilder.java index d0d601ce..0c68e00d 100644 --- a/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/StateMachineBuilder.java +++ b/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/StateMachineBuilder.java @@ -205,6 +205,11 @@ MutableState defineTimedState(S stateId, long initialDelay, * @param terminateEvent */ void defineTerminateEvent(E terminateEvent); + + /** + * Define default initial state for state machine started + */ + void defineDefaultInitialState(S stateId); /** * Define on entry actions for state @@ -222,14 +227,14 @@ MutableState defineTimedState(S stateId, long initialDelay, /** * Create a new state machine instance - * @param initialStateId initial state id + * @param initialStateId initial state id, null means using the default * @return new state machine instance */ T newStateMachine(S initialStateId); /** * Create new state machine instance according to state machine definition - * @param initialStateId the id of state machine initial state + * @param initialStateId the id of state machine initial state, null means using the default * @param extraParams other parameters for instantiate state machine * @return new state machine */ @@ -237,7 +242,7 @@ MutableState defineTimedState(S stateId, long initialDelay, /** * Create new state machine instance according to state machine definition - * @param initialStateId the id of state machine initial state + * @param initialStateId the id of state machine initial state, null means using the default * @param configuration configuration for state machine * @param extraParams other parameters for instantiate state machine * @return new state machine diff --git a/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/impl/StateMachineBuilderImpl.java b/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/impl/StateMachineBuilderImpl.java index e50ef668..0fe0497f 100644 --- a/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/impl/StateMachineBuilderImpl.java +++ b/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/impl/StateMachineBuilderImpl.java @@ -62,6 +62,8 @@ public class StateMachineBuilderImpl, S, E, C private final MvelScriptManager scriptManager; private E startEvent, finishEvent, terminateEvent; + + private S defaultInitStateId; private final ExecutionContext executionContext; @@ -701,6 +703,7 @@ public T newStateMachine(S initialStateId, Object... extraParams) { @Override public T newStateMachine(S initialStateId, StateMachineConfiguration configuration, Object... extraParams) { if(!prepared) prepare(); + if (initialStateId == null) initialStateId = defaultInitStateId; if(!isValidState(initialStateId)) { throw new IllegalArgumentException(getClass()+" cannot find Initial state \'"+ initialStateId+"\' in state machine."); @@ -923,6 +926,12 @@ public void defineTerminateEvent(E terminateEvent) { checkState(); this.terminateEvent = terminateEvent; } + + @Override + public void defineDefaultInitialState(S stateId) { + checkState(); + this.defaultInitStateId = stateId; + } void setScanAnnotations(boolean isScanAnnotations) { this.isScanAnnotations = isScanAnnotations; diff --git a/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/impl/StateMachineImporterImpl.java b/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/impl/StateMachineImporterImpl.java index b49839bc..10c64865 100644 --- a/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/impl/StateMachineImporterImpl.java +++ b/squirrel-foundation/src/main/java/org/squirrelframework/foundation/fsm/impl/StateMachineImporterImpl.java @@ -61,7 +61,9 @@ public class StateMachineImporterImpl, S, E, ArrayListMultimap.create(); protected Boolean isEntryAction; - + + protected String initStateIdName; + protected final Map reusableInstance = Maps.newHashMap(); public StateMachineImporterImpl() { @@ -138,6 +140,8 @@ public void startElement(String uri, String localName, String qName, currentStates.clear(); currentTranstionBuilder=null; + + stateMachineBuilder.defineDefaultInitialState(stateConverter.convertFromString(initStateIdName)); } else if(qName.equals("state") || qName.equals("final") || qName.equals("parallel")) { MutableState parentState = null; if(currentStates.size()>0) { @@ -252,6 +256,8 @@ public void startElement(String uri, String localName, String qName, } else if(condSchema.equals("mvel")) { getCurrentTranstionBuilder().whenMvel(condContent); } + } else if (qName.equals("scxml")) { + this.initStateIdName = attributes.getValue("initial"); } } diff --git a/squirrel-foundation/src/test/java/org/squirrelframework/foundation/fsm/DefaultInitialStateTest.java b/squirrel-foundation/src/test/java/org/squirrelframework/foundation/fsm/DefaultInitialStateTest.java new file mode 100644 index 00000000..f426709c --- /dev/null +++ b/squirrel-foundation/src/test/java/org/squirrelframework/foundation/fsm/DefaultInitialStateTest.java @@ -0,0 +1,47 @@ +package org.squirrelframework.foundation.fsm; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.squirrelframework.foundation.fsm.impl.AbstractStateMachine; + +public class DefaultInitialStateTest { + private StateMachineBuilder builder; + + @Before + public void setUp() throws Exception { + builder = StateMachineBuilderFactory.create(DefaultInitialStateMachine.class, TestState.class, TestEvent.class, Void.class); + builder.defineDefaultInitialState(TestState.A); + builder.transition().from(TestState.A).to(TestState.B).on(TestEvent.ToB); + builder.transition().from(TestState.B).to(TestState.C).on(TestEvent.ToC); + } + + @Test + public void defineInitialState() { + // define the initial state by builder.newStateMachine + DefaultInitialStateMachine initWithA = builder.newStateMachine(TestState.A); + Assert.assertEquals(TestState.A, initWithA.getInitialState()); + initWithA.fire(TestEvent.ToB); + Assert.assertEquals(TestState.B, initWithA.getCurrentState()); + + // define the initial state by builder.defineInitialStateId + DefaultInitialStateMachine initWithDefault = builder.newStateMachine(null); + Assert.assertEquals(TestState.A, initWithDefault.getInitialState()); + initWithDefault.fire(TestEvent.ToB); + Assert.assertEquals(TestState.B, initWithDefault.getCurrentState()); + } + + @Test + public void exportAndImport() { + DefaultInitialStateMachine stateMachine = builder.newStateMachine(null); + String sqrlScxml = stateMachine.exportXMLDefinition(true); + System.out.println(sqrlScxml); + + UntypedStateMachineBuilder builder = new UntypedStateMachineImporter().importDefinition(sqrlScxml); + DefaultInitialStateMachine recover = builder.newAnyStateMachine(null); + Assert.assertEquals(TestState.A, recover.getInitialState()); + } + + static class DefaultInitialStateMachine extends AbstractStateMachine { + } +}