From 83e59c2a60ef6c06f6889eb4c1389d4cc3d6e3ca Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sun, 23 Oct 2016 06:50:21 +0100 Subject: [PATCH] Add support for submachine refs - Relates to #262 --- .../data/jpa/JpaRepositoryState.java | 16 ++++-- .../data/jpa/JpaRepositoryTests.java | 30 +++++++++++ .../jpa/src/test/resources/data13.json | 50 +++++++++++++++++++ .../statemachine/data/RepositoryState.java | 8 +++ .../RepositoryStateMachineModelFactory.java | 19 +++++++ 5 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 spring-statemachine-data/jpa/src/test/resources/data13.json diff --git a/spring-statemachine-data/jpa/src/main/java/org/springframework/statemachine/data/jpa/JpaRepositoryState.java b/spring-statemachine-data/jpa/src/main/java/org/springframework/statemachine/data/jpa/JpaRepositoryState.java index c3216ad0..bc39571d 100644 --- a/spring-statemachine-data/jpa/src/main/java/org/springframework/statemachine/data/jpa/JpaRepositoryState.java +++ b/spring-statemachine-data/jpa/src/main/java/org/springframework/statemachine/data/jpa/JpaRepositoryState.java @@ -51,6 +51,7 @@ public class JpaRepositoryState extends RepositoryState { private String region; private boolean initial; private PseudoStateKind kind; + private String submachineId; @OneToOne(fetch = FetchType.EAGER) private JpaRepositoryState parentState; @@ -227,11 +228,20 @@ public class JpaRepositoryState extends RepositoryState { this.deferredEvents = deferredEvents; } + @Override + public String getSubmachineId() { + return submachineId; + } + + public void setSubmachineId(String submachineId) { + this.submachineId = submachineId; + } + @Override public String toString() { return "JpaRepositoryState [id=" + id + ", machineId=" + machineId + ", state=" + state + ", region=" + region - + ", initial=" + initial + ", kind=" + kind + ", parentState=" + parentState + ", stateActions=" - + stateActions + ", entryActions=" + entryActions + ", exitActions=" + exitActions + ", deferredEvents=" - + deferredEvents + "]"; + + ", initial=" + initial + ", kind=" + kind + ", submachineId=" + submachineId + ", parentState=" + + parentState + ", stateActions=" + stateActions + ", entryActions=" + entryActions + ", exitActions=" + + exitActions + ", deferredEvents=" + deferredEvents + "]"; } } diff --git a/spring-statemachine-data/jpa/src/test/java/org/springframework/statemachine/data/jpa/JpaRepositoryTests.java b/spring-statemachine-data/jpa/src/test/java/org/springframework/statemachine/data/jpa/JpaRepositoryTests.java index 3d36bbe7..16fc82cd 100644 --- a/spring-statemachine-data/jpa/src/test/java/org/springframework/statemachine/data/jpa/JpaRepositoryTests.java +++ b/spring-statemachine-data/jpa/src/test/java/org/springframework/statemachine/data/jpa/JpaRepositoryTests.java @@ -515,6 +515,25 @@ public class JpaRepositoryTests extends AbstractJpaRepositoryTests { plan.test(); } + @SuppressWarnings("unchecked") + @Test + public void testMachine13() throws Exception { + context.register(Config13.class, FactoryConfig.class); + context.refresh(); + StateMachineFactory stateMachineFactory = context.getBean(StateMachineFactory.class); + StateMachine stateMachine = stateMachineFactory.getStateMachine(); + + StateMachineTestPlan plan = + StateMachineTestPlanBuilder.builder() + .stateMachine(stateMachine) + .step().expectStates("S1").and() + .step().sendEvent("E1").expectStates("S2", "S21").and() + .step().sendEvent("E3").expectStates("S2", "S22").and() + .step().sendEvent("E2").expectStates("S3").and() + .build(); + plan.test(); + } + @Test public void testPopulate1() { context.register(Config2.class); @@ -729,6 +748,17 @@ public class JpaRepositoryTests extends AbstractJpaRepositoryTests { } } + @EnableAutoConfiguration + static class Config13 { + + @Bean + public StateMachineJackson2RepositoryPopulatorFactoryBean jackson2RepositoryPopulatorFactoryBean() { + StateMachineJackson2RepositoryPopulatorFactoryBean factoryBean = new StateMachineJackson2RepositoryPopulatorFactoryBean(); + factoryBean.setResources(new Resource[]{new ClassPathResource("data13.json")}); + return factoryBean; + } + } + @Configuration @EnableStateMachineFactory public static class FactoryConfig extends StateMachineConfigurerAdapter { diff --git a/spring-statemachine-data/jpa/src/test/resources/data13.json b/spring-statemachine-data/jpa/src/test/resources/data13.json new file mode 100644 index 00000000..ff5e176d --- /dev/null +++ b/spring-statemachine-data/jpa/src/test/resources/data13.json @@ -0,0 +1,50 @@ +[ + { + "@id": "1", + "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState", + "initial": true, + "state": "S1" + }, + { + "@id": "2", + "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState", + "submachineId": "machineS2", + "state": "S2" + }, + { + "@id": "3", + "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState", + "state": "S3" + }, + { + "@id": "4", + "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState", + "machineId": "machineS2", + "initial": true, + "state": "S21" + }, + { + "@id": "5", + "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryState", + "machineId": "machineS2", + "state": "S22" + }, + { + "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition", + "source": "1", + "target": "2", + "event": "E1" + }, + { + "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition", + "source": "2", + "target": "3", + "event": "E2" + }, + { + "_class": "org.springframework.statemachine.data.jpa.JpaRepositoryTransition", + "source": "4", + "target": "5", + "event": "E3" + } +] diff --git a/spring-statemachine-data/src/main/java/org/springframework/statemachine/data/RepositoryState.java b/spring-statemachine-data/src/main/java/org/springframework/statemachine/data/RepositoryState.java index 0ddba17f..f12752ac 100644 --- a/spring-statemachine-data/src/main/java/org/springframework/statemachine/data/RepositoryState.java +++ b/spring-statemachine-data/src/main/java/org/springframework/statemachine/data/RepositoryState.java @@ -96,4 +96,12 @@ public abstract class RepositoryState extends BaseRepositoryEntity { * @return the deferred events */ public abstract Set getDeferredEvents(); + + /** + * Gets the submachine id indicating that this is a submachine state + * and its structure is available from particular machine itself. + * + * @return the submachine id + */ + public abstract String getSubmachineId(); } diff --git a/spring-statemachine-data/src/main/java/org/springframework/statemachine/data/RepositoryStateMachineModelFactory.java b/spring-statemachine-data/src/main/java/org/springframework/statemachine/data/RepositoryStateMachineModelFactory.java index e514f1b7..f5570496 100644 --- a/spring-statemachine-data/src/main/java/org/springframework/statemachine/data/RepositoryStateMachineModelFactory.java +++ b/spring-statemachine-data/src/main/java/org/springframework/statemachine/data/RepositoryStateMachineModelFactory.java @@ -85,6 +85,13 @@ public class RepositoryStateMachineModelFactory extends AbstractStateMachineMode Collection> stateDatas = new ArrayList<>(); for (RepositoryState s : stateRepository.findByMachineId(machineId)) { + // do recursive build to get states for a submachine + StateMachineModel subStateMachineModel = null; + String submachineId = s.getSubmachineId(); + if (submachineId != null) { + subStateMachineModel = build(submachineId); + } + Collection> stateActions = new ArrayList>(); Set repositoryStateActions = s.getStateActions(); if (repositoryStateActions != null) { @@ -156,6 +163,18 @@ public class RepositoryStateMachineModelFactory extends AbstractStateMachineMode } } stateData.setDeferred(s.getDeferredEvents()); + + if (subStateMachineModel != null) { + // copy are set parent as state we're currently on + Collection> submachineStateData = new ArrayList<>(); + Collection> submachineStateDataOrig = subStateMachineModel.getStatesData().getStateData(); + for (StateData sd : submachineStateDataOrig) { + submachineStateData.add(new StateData(s.getState(), sd.getRegion(), sd.getState(), + sd.getDeferred(), sd.getEntryActions(), sd.getExitActions(), sd.isInitial())); + } + stateData.setSubmachineStateData(submachineStateData); + } + stateDatas.add(stateData); } StatesData statesData = new StatesData<>(stateDatas);