From e998ae44aac0d6eab3fabc4baa88c984ad83cd90 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 27 Oct 2016 19:35:28 +0200 Subject: [PATCH] add skipOnFirstNonTriggeredRule parameter (issue #52) --- .../easyrules/core/DefaultRulesEngine.java | 6 + .../easyrules/core/RulesEngineBuilder.java | 5 + .../easyrules/core/RulesEngineParameters.java | 13 +++ .../core/SkipOnFirstNonTrigeredRuleTest.java | 103 ++++++++++++++++++ .../spring/RulesEngineFactoryBean.java | 9 +- .../spring/RulesEngineFactoryBeanTest.java | 7 +- 6 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 easyrules-core/src/test/java/org/easyrules/core/SkipOnFirstNonTrigeredRuleTest.java diff --git a/easyrules-core/src/main/java/org/easyrules/core/DefaultRulesEngine.java b/easyrules-core/src/main/java/org/easyrules/core/DefaultRulesEngine.java index 30d9ce6..aac2f46 100644 --- a/easyrules-core/src/main/java/org/easyrules/core/DefaultRulesEngine.java +++ b/easyrules-core/src/main/java/org/easyrules/core/DefaultRulesEngine.java @@ -177,6 +177,11 @@ class DefaultRulesEngine implements RulesEngine { } } else { LOGGER.log(Level.INFO, "Rule ''{0}'' has been evaluated to false, it has not been executed", name); + + if (parameters.isSkipOnFirstNonTriggeredRule()) { + LOGGER.info("Next rules will be skipped since parameter skipOnFirstNonTriggeredRule is set"); + break; + } } } @@ -218,6 +223,7 @@ class DefaultRulesEngine implements RulesEngine { LOGGER.log(Level.INFO, "Engine name: {0}", parameters.getName()); LOGGER.log(Level.INFO, "Rule priority threshold: {0}", parameters.getPriorityThreshold()); LOGGER.log(Level.INFO, "Skip on first applied rule: {0}", parameters.isSkipOnFirstAppliedRule()); + LOGGER.log(Level.INFO, "Skip on first non triggered rule: {0}", parameters.isSkipOnFirstNonTriggeredRule()); LOGGER.log(Level.INFO, "Skip on first failed rule: {0}", parameters.isSkipOnFirstFailedRule()); } diff --git a/easyrules-core/src/main/java/org/easyrules/core/RulesEngineBuilder.java b/easyrules-core/src/main/java/org/easyrules/core/RulesEngineBuilder.java index eb51255..37af06b 100644 --- a/easyrules-core/src/main/java/org/easyrules/core/RulesEngineBuilder.java +++ b/easyrules-core/src/main/java/org/easyrules/core/RulesEngineBuilder.java @@ -37,6 +37,11 @@ public class RulesEngineBuilder { return this; } + public RulesEngineBuilder withSkipOnFirstNonTriggeredRule(final boolean skipOnFirstNonTriggeredRule) { + parameters.setSkipOnFirstNonTriggeredRule(skipOnFirstNonTriggeredRule); + return this; + } + public RulesEngineBuilder withSkipOnFirstFailedRule(final boolean skipOnFirstFailedRule) { parameters.setSkipOnFirstFailedRule(skipOnFirstFailedRule); return this; diff --git a/easyrules-core/src/main/java/org/easyrules/core/RulesEngineParameters.java b/easyrules-core/src/main/java/org/easyrules/core/RulesEngineParameters.java index 46cd194..fbe04d8 100644 --- a/easyrules-core/src/main/java/org/easyrules/core/RulesEngineParameters.java +++ b/easyrules-core/src/main/java/org/easyrules/core/RulesEngineParameters.java @@ -17,6 +17,11 @@ public class RulesEngineParameters { */ private boolean skipOnFirstAppliedRule; + /** + * Parameter to skip next applicable rules when a rule is non triggered + */ + private boolean skipOnFirstNonTriggeredRule; + /** * Parameter to skip next applicable rules when a rule has failed. */ @@ -72,6 +77,14 @@ public class RulesEngineParameters { this.skipOnFirstAppliedRule = skipOnFirstAppliedRule; } + public boolean isSkipOnFirstNonTriggeredRule() { + return skipOnFirstNonTriggeredRule; + } + + public void setSkipOnFirstNonTriggeredRule(boolean skipOnFirstNonTriggeredRule) { + this.skipOnFirstNonTriggeredRule = skipOnFirstNonTriggeredRule; + } + public boolean isSkipOnFirstFailedRule() { return skipOnFirstFailedRule; } diff --git a/easyrules-core/src/test/java/org/easyrules/core/SkipOnFirstNonTrigeredRuleTest.java b/easyrules-core/src/test/java/org/easyrules/core/SkipOnFirstNonTrigeredRuleTest.java new file mode 100644 index 0000000..a583ded --- /dev/null +++ b/easyrules-core/src/test/java/org/easyrules/core/SkipOnFirstNonTrigeredRuleTest.java @@ -0,0 +1,103 @@ +/* + * The MIT License + * + * Copyright (c) 2014, Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.easyrules.core; + +import org.easyrules.api.RulesEngine; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.mockito.Mockito.*; + +/** + * Test class of "skip on first non triggered rule" parameter of Easy Rules default engine. + * + * @author Krzysztof Kozlowski (krzysztof.kozlowski@coderion.pl) + */ +@RunWith(MockitoJUnitRunner.class) +public class SkipOnFirstNonTrigeredRuleTest { + + @Mock + private BasicRule rule0, rule1, rule2; + + private RulesEngine rulesEngine; + + @Before + public void setup() throws Exception { + + setUpRule0(); + setUpRule1(); + setUpRule2(); + + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withSkipOnFirstNonTriggeredRule(true) + .build(); + } + + @Test + public void testSkipOnFirstNonTriggeredRule() throws Exception { + + rulesEngine.registerRule(rule0); + rulesEngine.registerRule(rule1); + rulesEngine.registerRule(rule2); + + rulesEngine.fireRules(); + + //Rule 0 is normally executed + verify(rule0).execute(); + + //Rule1 is non triggered + verify(rule1, never()).execute(); + + //Rule 2 should be skipped since Rule 1 has not been executed + verify(rule2, never()).execute(); + + } + + private void setUpRule2() { + when(rule2.getName()).thenReturn("r2"); + when(rule2.getPriority()).thenReturn(2); + when(rule2.evaluate()).thenReturn(true); + when(rule2.compareTo(rule0)).thenReturn(1); + when(rule2.compareTo(rule1)).thenReturn(1); + } + + private void setUpRule1() { + when(rule1.getName()).thenReturn("r1"); + when(rule1.getPriority()).thenReturn(1); + when(rule1.evaluate()).thenReturn(false); + when(rule1.compareTo(rule0)).thenReturn(1); + } + + private void setUpRule0() throws Exception { + when(rule0.getName()).thenReturn("r0"); + when(rule0.getPriority()).thenReturn(0); + when(rule0.evaluate()).thenReturn(true); + when(rule0.compareTo(rule1)).thenReturn(-1); + } + +} diff --git a/easyrules-spring/src/main/java/org/easyrules/spring/RulesEngineFactoryBean.java b/easyrules-spring/src/main/java/org/easyrules/spring/RulesEngineFactoryBean.java index 2e1961c..d5d4579 100755 --- a/easyrules-spring/src/main/java/org/easyrules/spring/RulesEngineFactoryBean.java +++ b/easyrules-spring/src/main/java/org/easyrules/spring/RulesEngineFactoryBean.java @@ -46,7 +46,9 @@ public class RulesEngineFactoryBean implements FactoryBean { private int priorityThreshold = DEFAULT_RULE_PRIORITY_THRESHOLD; private boolean skipOnFirstAppliedRule; - + + private boolean skipOnFirstNonTriggeredRule; + private boolean skipOnFirstFailedRule; private boolean silentMode; @@ -60,6 +62,7 @@ public class RulesEngineFactoryBean implements FactoryBean { RulesEngineBuilder rulesEngineBuilder = aNewRulesEngine() .named(name) .withSkipOnFirstAppliedRule(skipOnFirstAppliedRule) + .withSkipOnFirstNonTriggeredRule(skipOnFirstNonTriggeredRule) .withSkipOnFirstFailedRule(skipOnFirstFailedRule) .withRulePriorityThreshold(priorityThreshold) .withSilentMode(silentMode); @@ -119,6 +122,10 @@ public class RulesEngineFactoryBean implements FactoryBean { this.skipOnFirstAppliedRule = skipOnFirstAppliedRule; } + public void setSkipOnFirstNonTriggeredRule(boolean skipOnFirstNonTriggeredRule) { + this.skipOnFirstNonTriggeredRule = skipOnFirstNonTriggeredRule; + } + public void setSkipOnFirstFailedRule(boolean skipOnFirstFailedRule) { this.skipOnFirstFailedRule = skipOnFirstFailedRule; } diff --git a/easyrules-spring/src/test/java/org/easyrules/spring/RulesEngineFactoryBeanTest.java b/easyrules-spring/src/test/java/org/easyrules/spring/RulesEngineFactoryBeanTest.java index 3f9317e..5ccd20a 100755 --- a/easyrules-spring/src/test/java/org/easyrules/spring/RulesEngineFactoryBeanTest.java +++ b/easyrules-spring/src/test/java/org/easyrules/spring/RulesEngineFactoryBeanTest.java @@ -64,6 +64,8 @@ public class RulesEngineFactoryBeanTest { private boolean skipOnFirstAppliedRule; + private boolean skipOnFirstNonTriggeredRule; + private boolean skipOnFirstFailedRule; private boolean silentMode; @@ -74,8 +76,9 @@ public class RulesEngineFactoryBeanTest { public void setUp() { name = NAME; silentMode = true; - skipOnFirstFailedRule = true; skipOnFirstAppliedRule = true; + skipOnFirstNonTriggeredRule = true; + skipOnFirstFailedRule = true; priorityThreshold = RULE_PRIORITY_THRESHOLD; rulesEngineFactoryBean = new RulesEngineFactoryBean(); } @@ -90,6 +93,7 @@ public class RulesEngineFactoryBeanTest { rulesEngineFactoryBean.setRuleListeners(expectedRuleListeners); rulesEngineFactoryBean.setPriorityThreshold(priorityThreshold); rulesEngineFactoryBean.setSkipOnFirstAppliedRule(skipOnFirstAppliedRule); + rulesEngineFactoryBean.setSkipOnFirstNonTriggeredRule(skipOnFirstNonTriggeredRule); rulesEngineFactoryBean.setSkipOnFirstFailedRule(skipOnFirstFailedRule); rulesEngineFactoryBean.setSilentMode(silentMode); rulesEngineFactoryBean.setName(name); @@ -101,6 +105,7 @@ public class RulesEngineFactoryBeanTest { assertThat(rulesEngineParameters.getName()).isEqualTo(NAME); assertThat(rulesEngineParameters.getPriorityThreshold()).isEqualTo(RULE_PRIORITY_THRESHOLD); assertThat(rulesEngineParameters.isSkipOnFirstAppliedRule()).isTrue(); + assertThat(rulesEngineParameters.isSkipOnFirstNonTriggeredRule()).isTrue(); assertThat(rulesEngineParameters.isSkipOnFirstFailedRule()).isTrue(); assertThat(rulesEngine.getRules()).isEqualTo(new HashSet<>(expectedRules)); assertThat(rulesEngine.getRuleListeners()).isEqualTo(expectedRuleListeners);