From a74e82a8f92bf926d10e35545616b618c2ee2cec Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Sat, 30 Apr 2016 09:22:27 +0100 Subject: [PATCH] Fix missing guards in uml model - Add defined guards to normal transitions. - Fixes #212 --- .../uml/support/UmlModelParser.java | 40 +++-- .../uml/UmlStateMachineModelFactoryTests.java | 61 ++++++++ .../statemachine/uml/simple-guards.di | 2 + .../statemachine/uml/simple-guards.notation | 147 ++++++++++++++++++ .../statemachine/uml/simple-guards.uml | 37 +++++ 5 files changed, 266 insertions(+), 21 deletions(-) create mode 100644 spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.di create mode 100644 spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.notation create mode 100644 spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.uml diff --git a/spring-statemachine-uml/src/main/java/org/springframework/statemachine/uml/support/UmlModelParser.java b/spring-statemachine-uml/src/main/java/org/springframework/statemachine/uml/support/UmlModelParser.java index ce9d3f36..02938612 100644 --- a/spring-statemachine-uml/src/main/java/org/springframework/statemachine/uml/support/UmlModelParser.java +++ b/spring-statemachine-uml/src/main/java/org/springframework/statemachine/uml/support/UmlModelParser.java @@ -219,15 +219,7 @@ public class UmlModelParser { list = new LinkedList>(); choices.put(transition.getSource().getName(), list); } - Guard guard = null; - for (Constraint c : transition.getOwnedRules()) { - if (c.getSpecification() instanceof OpaqueExpression) { - String beanId = UmlUtils.resolveBodyByLanguage(LANGUAGE_BEAN, (OpaqueExpression)c.getSpecification()); - if (StringUtils.hasText(beanId)) { - guard = resolver.resolveGuard(beanId); - } - } - } + Guard guard = resolveGuard(transition); // we want null guards to be at the end if (guard == null) { list.addLast(new ChoiceData(transition.getSource().getName(), transition.getTarget().getName(), guard)); @@ -240,15 +232,7 @@ public class UmlModelParser { list = new LinkedList>(); junctions.put(transition.getSource().getName(), list); } - Guard guard = null; - for (Constraint c : transition.getOwnedRules()) { - if (c.getSpecification() instanceof OpaqueExpression) { - String beanId = UmlUtils.resolveBodyByLanguage(LANGUAGE_BEAN, (OpaqueExpression)c.getSpecification()); - if (StringUtils.hasText(beanId)) { - guard = resolver.resolveGuard(beanId); - } - } - } + Guard guard = resolveGuard(transition); // we want null guards to be at the end if (guard == null) { list.addLast(new JunctionData(transition.getSource().getName(), transition.getTarget().getName(), guard)); @@ -282,12 +266,13 @@ public class UmlModelParser { // go through all triggers and create transition // from signals, or transitions from timers for (Trigger trigger : transition.getTriggers()) { + Guard guard = resolveGuard(transition); Event event = trigger.getEvent(); if (event instanceof SignalEvent) { Signal signal = ((SignalEvent)event).getSignal(); if (signal != null) { transitionDatas.add(new TransitionData(transition.getSource().getName(), - transition.getTarget().getName(), signal.getName(), resolveTransitionActions(transition), null, + transition.getTarget().getName(), signal.getName(), resolveTransitionActions(transition), guard, UmlUtils.mapUmlTransitionType(transition))); } } else if (event instanceof TimeEvent) { @@ -299,7 +284,7 @@ public class UmlModelParser { count = 1; } transitionDatas.add(new TransitionData(transition.getSource().getName(), - transition.getTarget().getName(), period, count, resolveTransitionActions(transition), null, + transition.getTarget().getName(), period, count, resolveTransitionActions(transition), guard, UmlUtils.mapUmlTransitionType(transition))); } } @@ -308,11 +293,24 @@ public class UmlModelParser { // create anonymous transition if needed if (shouldCreateAnonymousTransition(transition)) { transitionDatas.add(new TransitionData(transition.getSource().getName(), transition.getTarget().getName(), - null, resolveTransitionActions(transition), null, UmlUtils.mapUmlTransitionType(transition))); + null, resolveTransitionActions(transition), resolveGuard(transition), UmlUtils.mapUmlTransitionType(transition))); } } } + private Guard resolveGuard(Transition transition) { + Guard guard = null; + for (Constraint c : transition.getOwnedRules()) { + if (c.getSpecification() instanceof OpaqueExpression) { + String beanId = UmlUtils.resolveBodyByLanguage(LANGUAGE_BEAN, (OpaqueExpression)c.getSpecification()); + if (StringUtils.hasText(beanId)) { + guard = resolver.resolveGuard(beanId); + } + } + } + return guard; + } + private Long getTimePeriod(TimeEvent event) { try { return Long.valueOf(event.getWhen().getExpr().integerValue()); diff --git a/spring-statemachine-uml/src/test/java/org/springframework/statemachine/uml/UmlStateMachineModelFactoryTests.java b/spring-statemachine-uml/src/test/java/org/springframework/statemachine/uml/UmlStateMachineModelFactoryTests.java index ab87ed0b..62b622dd 100644 --- a/spring-statemachine-uml/src/test/java/org/springframework/statemachine/uml/UmlStateMachineModelFactoryTests.java +++ b/spring-statemachine-uml/src/test/java/org/springframework/statemachine/uml/UmlStateMachineModelFactoryTests.java @@ -502,6 +502,30 @@ public class UmlStateMachineModelFactoryTests extends AbstractUmlTests { assertThat(stateMachine.getState().getIds(), containsInAnyOrder("S5")); } + @Test + @SuppressWarnings("unchecked") + public void testSimpleGuardsDeny1() throws Exception { + context.register(Config14.class); + context.refresh(); + StateMachine stateMachine = context.getBean(StateMachine.class); + stateMachine.start(); + assertThat(stateMachine.getState().getIds(), containsInAnyOrder("S1")); + stateMachine.sendEvent("E1"); + assertThat(stateMachine.getState().getIds(), containsInAnyOrder("S1")); + } + + @Test + @SuppressWarnings("unchecked") + public void testSimpleGuardsDeny2() throws Exception { + context.register(Config14.class); + context.refresh(); + StateMachine stateMachine = context.getBean(StateMachine.class); + stateMachine.start(); + assertThat(stateMachine.getState().getIds(), containsInAnyOrder("S1")); + stateMachine.sendEvent("E2"); + assertThat(stateMachine.getState().getIds(), containsInAnyOrder("S3")); + } + @Configuration @EnableStateMachine public static class Config2 extends StateMachineConfigurerAdapter { @@ -765,6 +789,28 @@ public class UmlStateMachineModelFactoryTests extends AbstractUmlTests { } } + @Configuration + @EnableStateMachine + public static class Config14 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/uml/simple-guards.uml"); + } + + @Bean + public SimpleGuard denyGuard() { + return new SimpleGuard(false); + } + } + public static class LatchAction implements Action { CountDownLatch latch = new CountDownLatch(1); @Override @@ -787,6 +833,21 @@ public class UmlStateMachineModelFactoryTests extends AbstractUmlTests { } } + private static class SimpleGuard implements Guard { + + private final boolean deny; + + public SimpleGuard(boolean deny) { + this.deny = deny; + } + + @Override + public boolean evaluate(StateContext context) { + return deny; + } + } + + private static class JunctionGuard implements Guard { private final String match; diff --git a/spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.di b/spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.di new file mode 100644 index 00000000..bf9abab3 --- /dev/null +++ b/spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.di @@ -0,0 +1,2 @@ + + diff --git a/spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.notation b/spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.notation new file mode 100644 index 00000000..764b4655 --- /dev/null +++ b/spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.notation @@ -0,0 +1,147 @@ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.uml b/spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.uml new file mode 100644 index 00000000..c00c3d54 --- /dev/null +++ b/spring-statemachine-uml/src/test/resources/org/springframework/statemachine/uml/simple-guards.uml @@ -0,0 +1,37 @@ + + + + + + + + + bean + denyGuard + + + + + + + + + + + bean + denyGuard + + + + + + + + + + + + + + +