From c18f7eb1bbdc59540b03c248e786e1dede9a42be Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Fri, 19 May 2017 00:30:25 +0200 Subject: [PATCH] rename base package to org.jeasy.rules after moving to jeasy organisation --- README.md | 51 ++-- .../pom.xml | 18 +- .../resources/META-INF/maven/archetype.xml | 2 +- .../resources/archetype-resources/pom.xml | 6 +- .../src/main/java/HelloWorldRule.java | 6 +- .../src/main/java/Launcher.java | 4 +- {easyrules-core => easy-rules-core}/pom.xml | 16 +- .../org/jeasy/rules/annotation/Action.java | 47 ++++ .../org/jeasy/rules/annotation/Condition.java | 40 +++ .../java/org/jeasy/rules/annotation/Fact.java | 39 +++ .../org/jeasy/rules/annotation/Priority.java | 40 +++ .../java/org/jeasy/rules/annotation/Rule.java | 51 ++++ .../jeasy/rules/annotation/package-info.java | 27 ++ .../main/java/org/jeasy/rules/api/Facts.java | 61 ++++ .../main/java/org/jeasy/rules/api/Rule.java | 80 ++++++ .../org/jeasy/rules/api/RuleListener.java | 75 +++++ .../main/java/org/jeasy/rules/api/Rules.java | 75 +++++ .../java/org/jeasy/rules/api/RulesEngine.java | 72 +++++ .../org/jeasy/rules/api/package-info.java | 27 ++ .../rules/core/ActionMethodOrderBean.java | 83 ++++++ .../java/org/jeasy/rules/core/BasicRule.java | 172 +++++++++++ .../org/jeasy/rules/core/CompositeRule.java | 141 ++++++++++ .../jeasy/rules/core/DefaultRulesEngine.java | 220 +++++++++++++++ .../rules/core/RuleDefinitionValidator.java | 161 +++++++++++ .../java/org/jeasy/rules/core/RuleProxy.java | 245 ++++++++++++++++ .../jeasy/rules/core/RulesEngineBuilder.java | 91 ++++++ .../rules/core/RulesEngineParameters.java | 125 ++++++++ .../main/java/org/jeasy/rules/core/Utils.java | 109 +++++++ .../org/jeasy/rules/core/package-info.java | 27 ++ .../src/main/resources/logging.properties | 0 .../org/jeasy/rules/EasyRulesTestSuite.java | 54 ++++ ...MethodHavingOneArgumentNotOfTypeFacts.java | 47 ++++ ...itionMethodHavingNonBooleanReturnType.java | 45 +++ ...MethodHavingOneArgumentNotOfTypeFacts.java | 45 +++ .../AnnotatedRuleWithMetaRuleAnnotation.java | 37 +++ ...atedRuleWithMoreThanOnePriorityMethod.java | 55 ++++ ...nnotatedRuleWithNotPublicActionMethod.java | 45 +++ ...tatedRuleWithNotPublicConditionMethod.java | 45 +++ ...otatedRuleWithNotPublicPriorityMethod.java | 50 ++++ ...RuleWithPriorityMethodHavingArguments.java | 50 ++++ ...orityMethodHavingNonIntegerReturnType.java | 50 ++++ .../AnnotatedRuleWithoutActionMethod.java | 44 +++ .../AnnotatedRuleWithoutCondition.java | 44 +++ .../org/jeasy/rules/annotation/MetaRule.java | 35 +++ .../org/jeasy/rules/core/AbstractTest.java | 58 ++++ .../jeasy/rules/core/AnnotatedRulesTest.java | 83 ++++++ .../rules/core/AnnotationInheritanceTest.java | 68 +++++ .../org/jeasy/rules/core/BasicRuleTest.java | 112 ++++++++ .../jeasy/rules/core/CompositeRuleTest.java | 171 +++++++++++ .../rules/core/CustomRuleOrderingTest.java | 84 ++++++ .../rules/core/DefaultRulesEngineTest.java | 266 ++++++++++++++++++ .../core/RuleDefinitionValidatorTest.java | 117 ++++++++ .../jeasy/rules/core/RuleListenerTest.java | 158 +++++++++++ .../rules/core/RulePriorityThresholdTest.java | 68 +++++ .../org/jeasy/rules/core/RuleProxyTest.java | 43 +++ .../rules/core/RulesEngineBuilderTest.java | 81 ++++++ .../core/SkipOnFirstAppliedRuleTest.java | 80 ++++++ .../rules/core/SkipOnFirstFailedRuleTest.java | 68 +++++ .../core/SkipOnFirstNonTriggeredRuleTest.java | 66 +++++ .../java/org/jeasy/rules/core/UtilsTest.java | 95 +++++++ .../README.md | 0 .../build.gradle | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../gradlew | 0 .../gradlew.bat | 168 +++++------ .../easyrules/samples/fire/Launcher.groovy | 2 +- .../easyrules/samples/fire/TheWorld.groovy | 0 .../easyrules/samples/fire/beans/Alarm.groovy | 0 .../easyrules/samples/fire/beans/Fire.groovy | 0 .../easyrules/samples/fire/beans/Room.groovy | 0 .../samples/fire/beans/Sprinkler.groovy | 0 .../samples/fire/rules/CancelAlarmRule.groovy | 8 +- .../fire/rules/EverythingOKRule.groovy | 8 +- .../samples/fire/rules/RaiseAlarmRule.groovy | 8 +- .../fire/rules/ThereIsAnAlarmRule.groovy | 8 +- .../fire/rules/TurnSprinklerOffRule.groovy | 8 +- .../fire/rules/TurnSprinklerOnRule.groovy | 8 +- .../samples/fizzbuzz/BuzzRule.groovy | 8 +- .../samples/fizzbuzz/FizzBuzz.groovy | 0 .../samples/fizzbuzz/FizzBuzzRule.groovy | 2 +- .../fizzbuzz/FizzBuzzWithEasyRules.groovy | 2 +- .../samples/fizzbuzz/FizzRule.groovy | 8 +- .../samples/fizzbuzz/NonFizzBuzzRule.groovy | 8 +- .../samples/helloworld/HelloWorldRule.groovy | 6 +- .../samples/helloworld/Launcher.groovy | 2 +- .../samples/scheduling/Launcher.groovy | 2 +- .../samples/scheduling/TimeRule.groovy | 6 +- .../org/easyrules/samples/shop/AgeRule.groovy | 2 +- .../easyrules/samples/shop/Launcher.groovy | 4 +- .../samples/shop/OkToSellRule.groovy | 6 +- .../org/easyrules/samples/shop/Person.groovy | 0 .../samples/shop/UnderAgeRule.groovy | 6 +- .../easyrules/samples/simple/Launcher.groovy | 2 +- .../samples/simple/SimpleRule.groovy | 8 +- .../easyrules/samples/spring/DummyRule.groovy | 6 +- .../easyrules/samples/spring/Launcher.groovy | 2 +- .../src/main/resources/logging.properties | 0 .../samples/spring/application-context.xml | 0 pom.xml | 22 +- 100 files changed, 4485 insertions(+), 210 deletions(-) rename {easyrules-archetype => easy-rules-archetype}/pom.xml (68%) rename {easyrules-archetype => easy-rules-archetype}/src/main/resources/META-INF/maven/archetype.xml (82%) rename {easyrules-archetype => easy-rules-archetype}/src/main/resources/archetype-resources/pom.xml (78%) rename {easyrules-archetype => easy-rules-archetype}/src/main/resources/archetype-resources/src/main/java/HelloWorldRule.java (93%) rename {easyrules-archetype => easy-rules-archetype}/src/main/resources/archetype-resources/src/main/java/Launcher.java (95%) rename {easyrules-core => easy-rules-core}/pom.xml (77%) create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/annotation/Action.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/annotation/Condition.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/annotation/Fact.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/annotation/Priority.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/annotation/Rule.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/annotation/package-info.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/api/Facts.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/api/Rule.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/api/RuleListener.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/api/Rules.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/api/RulesEngine.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/api/package-info.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/core/ActionMethodOrderBean.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/core/BasicRule.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/core/CompositeRule.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/core/DefaultRulesEngine.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/core/RuleDefinitionValidator.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/core/RulesEngineBuilder.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/core/RulesEngineParameters.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/core/Utils.java create mode 100644 easy-rules-core/src/main/java/org/jeasy/rules/core/package-info.java rename {easyrules-core => easy-rules-core}/src/main/resources/logging.properties (100%) create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/EasyRulesTestSuite.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithActionMethodHavingOneArgumentNotOfTypeFacts.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithConditionMethodHavingNonBooleanReturnType.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithConditionMethodHavingOneArgumentNotOfTypeFacts.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithMetaRuleAnnotation.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithMoreThanOnePriorityMethod.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicActionMethod.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicConditionMethod.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicPriorityMethod.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithPriorityMethodHavingArguments.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithPriorityMethodHavingNonIntegerReturnType.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithoutActionMethod.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithoutCondition.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/annotation/MetaRule.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/AbstractTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotatedRulesTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotationInheritanceTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/BasicRuleTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/CompositeRuleTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/CustomRuleOrderingTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/DefaultRulesEngineTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/RuleDefinitionValidatorTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/RuleListenerTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/RulePriorityThresholdTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/RuleProxyTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/RulesEngineBuilderTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstAppliedRuleTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstFailedRuleTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstNonTriggeredRuleTest.java create mode 100644 easy-rules-core/src/test/java/org/jeasy/rules/core/UtilsTest.java rename {easyrules-gradle => easy-rules-gradle}/README.md (100%) rename {easyrules-gradle => easy-rules-gradle}/build.gradle (100%) rename {easyrules-gradle => easy-rules-gradle}/gradle/wrapper/gradle-wrapper.jar (100%) rename {easyrules-gradle => easy-rules-gradle}/gradle/wrapper/gradle-wrapper.properties (100%) rename {easyrules-gradle => easy-rules-gradle}/gradlew (100%) rename {easyrules-gradle => easy-rules-gradle}/gradlew.bat (96%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/Launcher.groovy (96%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/TheWorld.groovy (100%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/beans/Alarm.groovy (100%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/beans/Fire.groovy (100%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/beans/Room.groovy (100%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/beans/Sprinkler.groovy (100%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/rules/CancelAlarmRule.groovy (71%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/rules/EverythingOKRule.groovy (70%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/rules/RaiseAlarmRule.groovy (72%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/rules/ThereIsAnAlarmRule.groovy (71%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOffRule.groovy (77%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOnRule.groovy (81%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fizzbuzz/BuzzRule.groovy (58%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzz.groovy (100%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzRule.groovy (83%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzWithEasyRules.groovy (96%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzRule.groovy (58%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/fizzbuzz/NonFizzBuzzRule.groovy (60%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/helloworld/HelloWorldRule.groovy (80%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/helloworld/Launcher.groovy (91%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/scheduling/Launcher.groovy (95%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/scheduling/TimeRule.groovy (76%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/shop/AgeRule.groovy (93%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/shop/Launcher.groovy (88%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/shop/OkToSellRule.groovy (77%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/shop/Person.groovy (100%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/shop/UnderAgeRule.groovy (78%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/simple/Launcher.groovy (88%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/simple/SimpleRule.groovy (55%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/spring/DummyRule.groovy (63%) rename {easyrules-gradle => easy-rules-gradle}/src/main/groovy/org/easyrules/samples/spring/Launcher.groovy (94%) rename {easyrules-gradle => easy-rules-gradle}/src/main/resources/logging.properties (100%) rename {easyrules-gradle => easy-rules-gradle}/src/main/resources/org/easyrules/samples/spring/application-context.xml (100%) diff --git a/README.md b/README.md index 18171d4..a051989 100644 --- a/README.md +++ b/README.md @@ -18,17 +18,17 @@ This is exactly what Easy Rules does, it provides the `Rule` abstraction to crea ##### First, define your rule.. ```java -@Rule(name = "my awesome rule" ) -public class MyRule { +@Rule(name = "weather rule", description = "if it rains then take an umbrella" ) +public class WeatherRule { @Condition - public boolean when() { - return true; + public boolean itRains(@Fact("rain") boolean rain) { + return rain; } @Action - public void then() { - System.out.println("Easy Rules rocks!"); + public void takeAnUmbrella() { + System.out.println("It rains, take an umbrella!"); } } ``` @@ -38,33 +38,36 @@ public class MyRule { ```java public class Test { public static void main(String[] args) { - // create a rules engine - RulesEngine rulesEngine = aNewRulesEngine().build(); - //register the rule - rulesEngine.registerRule(new MyRule()); - //fire rules - rulesEngine.fireRules(); + // define facts + Facts facts = new Facts(); + facts.add("rain", true); + + // define rules + Rules rules = new Rules(new WeatherRule()); + + // fire rules on known facts + RulesEngine rulesEngine = new DefaultRulesEngine(); + rulesEngine.fire(rules, facts); } } ``` -This is the hello world of Easy Rules. You can find other examples like the [FizzBuzz tutorial](http://www.easyrules.org/tutorials/fizzbuzz-tutorial.html) in the documentation. +This is the hello world of Easy Rules. You can find other examples like the [FizzBuzz tutorial](https://github.com/j-easy/easy-rules/wiki/fizz-buzz) in the wiki. ## Quick links -|Item |Link | -|:---------------------|:-------------------------------------------------------------------------------------| -|Project Home | [http://www.easyrules.org](http://www.easyrules.org) | -|Presentation | [https://speakerdeck.com/benas/easy-rules](https://speakerdeck.com/benas/easy-rules) | -|Continuous integration| [Build job @ Travis CI](https://travis-ci.org/EasyRules/easyrules) | -|Agile Board | [Backlog items @ waffle.io](https://waffle.io/EasyRules/easyrules) | -|Code coverage | [![Coverage](https://coveralls.io/repos/EasyRules/easyrules/badge.svg?style=flat&branch=master&service=github)](https://coveralls.io/github/EasyRules/easyrules?branch=master) | +|Item |Link | +|:---------------------|:--------------------------------------------------------------------------------------| +|Project Home | [https://github.com/j-easy/easy-rules/wiki](https://github.com/j-easy/easy-rules/wiki)| +|Presentation | [https://speakerdeck.com/benas/easy-rules](https://speakerdeck.com/benas/easy-rules) | +|Continuous integration| [Build job @ Travis CI](https://travis-ci.org/j-easy/easy-rules) | +|Code coverage | [![Coverage](https://coveralls.io/repos/j-easy/easy-rules/badge.svg?style=flat&branch=master&service=github)](https://coveralls.io/github/j-easy/easy-rules?branch=master) | |Sonar analysis | [![Quality Gate](https://sonarqube.com/api/badges/gate?key=org.easyrules:easyrules)](https://sonarqube.com/overview?id=org.easyrules%3Aeasyrules) | ## Current version -* The current stable version is `2.4.0` : [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.easyrules/easyrules-core/badge.svg?style=flat)](http://search.maven.org/#artifactdetails|org.easyrules|easyrules-core|2.4.0|) -* The current development version is `2.5.0-SNAPSHOT` : [![Build Status](https://travis-ci.org/EasyRules/easyrules.svg?branch=master)](https://travis-ci.org/EasyRules/easyrules) +* The current stable version is `2.5.0` : [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.easyrules/easyrules-core/badge.svg?style=flat)](http://search.maven.org/#artifactdetails|org.easyrules|easyrules-core|2.5.0|) +* The current development version is `3.0.0-SNAPSHOT` : [![Build Status](https://travis-ci.org/j-easy/easy-rules.svg?branch=master)](https://travis-ci.org/j-easy/easy-rules) In order to use snapshot versions, you need to add the following maven repository in your `pom.xml`: @@ -79,9 +82,9 @@ In order to use snapshot versions, you need to add the following maven repositor You are welcome to contribute to the project with pull requests on GitHub. -If you found a bug or want to request a feature, please use the [issue tracker](https://github.com/EasyRules/easyrules/issues). +If you found a bug or want to request a feature, please use the [issue tracker](https://github.com/j-easy/easy-rules/issues). -For any further question, you can use the [Gitter](https://gitter.im/EasyRules/easyrules) channel of the project. +For any further question, you can use the [Gitter](https://gitter.im/j-easy/easy-rules) channel of the project. ## Awesome contributors diff --git a/easyrules-archetype/pom.xml b/easy-rules-archetype/pom.xml similarity index 68% rename from easyrules-archetype/pom.xml rename to easy-rules-archetype/pom.xml index 23911be..03676c0 100755 --- a/easyrules-archetype/pom.xml +++ b/easy-rules-archetype/pom.xml @@ -1,15 +1,15 @@ - org.easyrules - easyrules + org.jeasy + easy-rules 3.0.0-SNAPSHOT 4.0.0 - easyrules-archetype + easy-rules-archetype Easy Rules Quick Start Archetype Maven archetype to create a skeleton project - http://www.easyrules.org + http://www.github.com/j-easy/easy-rules @@ -24,20 +24,20 @@ - git@github.com:EasyRules/easyrules.git - scm:git:git@github.com:EasyRules/easyrules.git - scm:git:git@github.com:EasyRules/easyrules.git + git@github.com:j-easy/easy-rules.git + scm:git:git@github.com:j-easy/easy-rules.git + scm:git:git@github.com:j-easy/easy-rules.git HEAD GitHub - https://github.com/EasyRules/easyrules/issues + https://github.com/j-easy/easy-rules/issues Travis CI - https://travis-ci.org/EasyRules/easyrules + https://travis-ci.org/j-easy/easy-rules diff --git a/easyrules-archetype/src/main/resources/META-INF/maven/archetype.xml b/easy-rules-archetype/src/main/resources/META-INF/maven/archetype.xml similarity index 82% rename from easyrules-archetype/src/main/resources/META-INF/maven/archetype.xml rename to easy-rules-archetype/src/main/resources/META-INF/maven/archetype.xml index 01894f9..5bda5c0 100755 --- a/easyrules-archetype/src/main/resources/META-INF/maven/archetype.xml +++ b/easy-rules-archetype/src/main/resources/META-INF/maven/archetype.xml @@ -1,5 +1,5 @@ - easyrules-archetype + easy-rules-archetype src/main/java/HelloWorldRule.java src/main/java/Launcher.java diff --git a/easyrules-archetype/src/main/resources/archetype-resources/pom.xml b/easy-rules-archetype/src/main/resources/archetype-resources/pom.xml similarity index 78% rename from easyrules-archetype/src/main/resources/archetype-resources/pom.xml rename to easy-rules-archetype/src/main/resources/archetype-resources/pom.xml index 7dc4d4b..ce6b3b6 100755 --- a/easyrules-archetype/src/main/resources/archetype-resources/pom.xml +++ b/easy-rules-archetype/src/main/resources/archetype-resources/pom.xml @@ -7,9 +7,9 @@ jar - org.easyrules - easyrules-core - 2.5.0 + org.jeasy + easy-rules-core + 3.0.0-SNAPSHOT diff --git a/easyrules-archetype/src/main/resources/archetype-resources/src/main/java/HelloWorldRule.java b/easy-rules-archetype/src/main/resources/archetype-resources/src/main/java/HelloWorldRule.java similarity index 93% rename from easyrules-archetype/src/main/resources/archetype-resources/src/main/java/HelloWorldRule.java rename to easy-rules-archetype/src/main/resources/archetype-resources/src/main/java/HelloWorldRule.java index 68434bc..ef72295 100644 --- a/easyrules-archetype/src/main/resources/archetype-resources/src/main/java/HelloWorldRule.java +++ b/easy-rules-archetype/src/main/resources/archetype-resources/src/main/java/HelloWorldRule.java @@ -23,9 +23,9 @@ */ package ${packageName}; -import org.easyrules.annotation.Action; -import org.easyrules.annotation.Condition; -import org.easyrules.annotation.Rule; +import org.jeasy.rules.annotation.Action; +import org.jeasy.rules.annotation.Condition; +import org.jeasy.rules.annotation.Rule; @Rule(name = "Hello World rule", description = "Say Hello to only duke's friends") public class HelloWorldRule { diff --git a/easyrules-archetype/src/main/resources/archetype-resources/src/main/java/Launcher.java b/easy-rules-archetype/src/main/resources/archetype-resources/src/main/java/Launcher.java similarity index 95% rename from easyrules-archetype/src/main/resources/archetype-resources/src/main/java/Launcher.java rename to easy-rules-archetype/src/main/resources/archetype-resources/src/main/java/Launcher.java index 45ab125..93620cc 100644 --- a/easyrules-archetype/src/main/resources/archetype-resources/src/main/java/Launcher.java +++ b/easy-rules-archetype/src/main/resources/archetype-resources/src/main/java/Launcher.java @@ -23,11 +23,11 @@ */ package ${packageName}; -import org.easyrules.api.RulesEngine; +import org.jeasy.rules.api.RulesEngine; import java.util.Scanner; -import static org.easyrules.core.RulesEngineBuilder.aNewRulesEngine; +import static org.jeasy.rules.core.RulesEngineBuilder.aNewRulesEngine; /** * Launcher class of the Hello World sample. diff --git a/easyrules-core/pom.xml b/easy-rules-core/pom.xml similarity index 77% rename from easyrules-core/pom.xml rename to easy-rules-core/pom.xml index 2615d12..c108504 100644 --- a/easyrules-core/pom.xml +++ b/easy-rules-core/pom.xml @@ -2,32 +2,32 @@ 4.0.0 - org.easyrules - easyrules + org.jeasy + easy-rules 3.0.0-SNAPSHOT - easyrules-core + easy-rules-core jar Easy Rules core module Public API and core implementation of Easy Rules - git@github.com:EasyRules/easyrules.git - scm:git:git@github.com:EasyRules/easyrules.git - scm:git:git@github.com:EasyRules/easyrules.git + git@github.com:j-easy/easy-rules.git + scm:git:git@github.com:j-easy/easy-rules.git + scm:git:git@github.com:j-easy/easy-rules.git HEAD GitHub - https://github.com/EasyRules/easyrules/issues + https://github.com/j-easy/easy-rules/issues Travis CI - https://travis-ci.org/EasyRules/easyrules + https://travis-ci.org/j-easy/easy-rules diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Action.java b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Action.java new file mode 100644 index 0000000..56b2b14 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Action.java @@ -0,0 +1,47 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +import java.lang.annotation.*; + +/** + * Annotation to mark a method as a rule action. + * Must annotate any public method with no arguments. + * The method return value will be ignored by the engine. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Action { + + /** + * The order in which the action should be executed. + * @return the order in which the action should be executed + */ + int order() default 0; + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Condition.java b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Condition.java new file mode 100644 index 0000000..30eebef --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Condition.java @@ -0,0 +1,40 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +import java.lang.annotation.*; + +/** + * Annotation to mark a method as a rule condition. + * Must annotate any public method with no arguments and that returns a boolean value. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Condition { + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Fact.java b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Fact.java new file mode 100644 index 0000000..1e1a5ec --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Fact.java @@ -0,0 +1,39 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +import java.lang.annotation.*; + +/** + * Annotation to mark a parameter as a fact. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.PARAMETER}) +public @interface Fact { + String value(); +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Priority.java b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Priority.java new file mode 100644 index 0000000..afd642f --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Priority.java @@ -0,0 +1,40 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +import java.lang.annotation.*; + +/** + * Annotation to mark the method to execute to get rule priority. + * Must annotate any public method with no arguments and that returns an integer value. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Priority { + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Rule.java b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Rule.java new file mode 100644 index 0000000..41c7a37 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/Rule.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +import java.lang.annotation.*; + +/** + * Annotation to mark a class as a rule. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Rule { + + /** + * The rule name which must be unique within an rules registry. + * @return The rule name + */ + String name() default org.jeasy.rules.api.Rule.DEFAULT_NAME; + + /** + * The rule description. + * @return The rule description + */ + String description() default org.jeasy.rules.api.Rule.DEFAULT_DESCRIPTION; + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/annotation/package-info.java b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/package-info.java new file mode 100644 index 0000000..74340d0 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/annotation/package-info.java @@ -0,0 +1,27 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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. + */ +/** + * This package contains Easy Rules annotations. + */ +package org.jeasy.rules.annotation; diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/api/Facts.java b/easy-rules-core/src/main/java/org/jeasy/rules/api/Facts.java new file mode 100644 index 0000000..723504d --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/api/Facts.java @@ -0,0 +1,61 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.api; + +import java.util.*; + +import static java.lang.String.format; + +public class Facts implements Iterable> { + + private Map facts = new HashMap<>(); + + public void add(String name, Object fact) { + facts.put(name, fact); + } + + public void remove(String name) { + facts.remove(name); + } + + public Object get(String name) { + return facts.get(name); + } + + @Override + public Iterator> iterator() { + return facts.entrySet().iterator(); + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder("Facts {").append("\n"); + for (Map.Entry fact : facts.entrySet()) { + stringBuilder.append(format(" Fact { %s : %s }", fact.getKey(), fact.getValue().toString())); + stringBuilder.append("\n"); + } + stringBuilder.append("}"); + return stringBuilder.toString(); + } +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/api/Rule.java b/easy-rules-core/src/main/java/org/jeasy/rules/api/Rule.java new file mode 100644 index 0000000..a11758a --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/api/Rule.java @@ -0,0 +1,80 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.api; + +/** + * Abstraction for a rule that can be fired by the rules engine. + * + * Rules are registered in the rules engine registry and must have a unique name. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public interface Rule extends Comparable { + + /** + * Default rule name. + */ + String DEFAULT_NAME = "rule"; + + /** + * Default rule description. + */ + String DEFAULT_DESCRIPTION = "description"; + + /** + * Default rule priority. + */ + int DEFAULT_PRIORITY = Integer.MAX_VALUE - 1; + + /** + * Getter for rule name. + * @return the rule name + */ + String getName(); + + /** + * Getter for rule description. + * @return rule description + */ + String getDescription(); + + /** + * Getter for rule priority. + * @return rule priority + */ + int getPriority(); + + /** + * Rule conditions abstraction : this method encapsulates the rule's conditions. + * @return true if the rule should be applied given the provided facts, false else + */ + boolean evaluate(Facts facts); + + /** + * Rule actions abstraction : this method encapsulates the rule's actions. + * @throws Exception thrown if an exception occurs during actions performing + */ + void execute(Facts facts) throws Exception; + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/api/RuleListener.java b/easy-rules-core/src/main/java/org/jeasy/rules/api/RuleListener.java new file mode 100644 index 0000000..5c37103 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/api/RuleListener.java @@ -0,0 +1,75 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.api; + +/** + * A listener for rules execution events. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public interface RuleListener { + + /** + * Triggered before the evaluation of a rule. + * + * @param rule being evaluated + * @param facts known before evaluating the rule + * @return true if the rule should be evaluated, false otherwise + */ + boolean beforeEvaluate(Rule rule, Facts facts); + + /** + * Triggered after the evaluation of a rule. + * + * @param rule that has been evaluated + * @param evaluationResult true if the rule evaluated to true, false otherwise + */ + void afterEvaluate(Rule rule, boolean evaluationResult); + + /** + * Triggered before the execution of a rule. + * + * @param rule the current rule + * @param rule known before executing the rule + */ + void beforeExecute(Rule rule, Facts facts); + + /** + * Triggered after a rule has been executed successfully. + * + * @param rule the current rule + * @param facts known after executing the rule + */ + void onSuccess(Rule rule, Facts facts); + + /** + * Triggered after a rule has failed. + * + * @param rule the current rule + * @param exception the exception thrown when attempting to execute the rule + * @param facts known after executing the rule + */ + void onFailure(Rule rule, Exception exception, Facts facts); + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/api/Rules.java b/easy-rules-core/src/main/java/org/jeasy/rules/api/Rules.java new file mode 100644 index 0000000..ed4ebdb --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/api/Rules.java @@ -0,0 +1,75 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.api; + +import org.jeasy.rules.core.RuleProxy; + +import java.util.Collections; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeSet; + +public class Rules implements Iterable { + + private Set rules = new TreeSet<>(); + + public Rules(Set rules) { + this.rules = rules; + } + + public Rules(Rule... rules ) { + Collections.addAll(this.rules, rules); + } + + public Rules(Object... rules ) { + for (Object rule : rules) { + this.register(RuleProxy.asRule(rule)); + } + } + + public void register(Object rule) { + rules.add(RuleProxy.asRule(rule)); + } + + public void unregister(Object rule) { + rules.remove(RuleProxy.asRule(rule)); + } + + public boolean isEmpty() { + return rules.isEmpty(); + } + + public void clear() { + rules.clear(); + } + + @Override + public Iterator iterator() { + return rules.iterator(); + } + + public void sort() { + rules = new TreeSet<>(rules); + } +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/api/RulesEngine.java b/easy-rules-core/src/main/java/org/jeasy/rules/api/RulesEngine.java new file mode 100644 index 0000000..3bea313 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/api/RulesEngine.java @@ -0,0 +1,72 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.api; + +import java.util.List; +import java.util.Map; + +import org.jeasy.rules.core.RulesEngineParameters; + +/** + * Rules engine interface. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public interface RulesEngine { + + /** + * Default engine name. + */ + String DEFAULT_NAME = "engine"; + + /** + * Default rule priority threshold. + */ + int DEFAULT_RULE_PRIORITY_THRESHOLD = Integer.MAX_VALUE; + + /** + * Return the rules engine parameters. + * + * @return The rules engine parameters + */ + RulesEngineParameters getParameters(); + + /** + * Return the list of registered rule listeners. + * + * @return the list of registered rule listeners + */ + List getRuleListeners(); + + /** + * Fire all registered rules on given facts. + */ + void fire(Rules rules, Facts facts); + + /** + * Check rules without firing them. + * @return a map with the result of evaluation of each rule + */ + Map check(Rules rules, Facts facts); +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/api/package-info.java b/easy-rules-core/src/main/java/org/jeasy/rules/api/package-info.java new file mode 100644 index 0000000..6566504 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/api/package-info.java @@ -0,0 +1,27 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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. + */ +/** + * This package contains Easy Rules public API. + */ +package org.jeasy.rules.api; diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/ActionMethodOrderBean.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/ActionMethodOrderBean.java new file mode 100644 index 0000000..aa69854 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/ActionMethodOrderBean.java @@ -0,0 +1,83 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import java.lang.reflect.Method; + +/** + * Utility class that associates an action method and its execution order. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +class ActionMethodOrderBean implements Comparable { + + private Method method; + + private int order; + + ActionMethodOrderBean(final Method method, final int order) { + this.method = method; + this.order = order; + } + + public int getOrder() { + return order; + } + + public Method getMethod() { + return method; + } + + @Override + public int compareTo(final ActionMethodOrderBean actionMethodOrderBean) { + if (order < actionMethodOrderBean.getOrder()) { + return -1; + } else if (order > actionMethodOrderBean.getOrder()) { + return 1; + } else { + return method.equals(actionMethodOrderBean.getMethod()) ? 0 : 1; + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof ActionMethodOrderBean)) return false; + + ActionMethodOrderBean that = (ActionMethodOrderBean) o; + + if (order != that.order) return false; + if (!method.equals(that.method)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = method.hashCode(); + result = 31 * result + order; + return result; + } + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/BasicRule.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/BasicRule.java new file mode 100644 index 0000000..7f96598 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/BasicRule.java @@ -0,0 +1,172 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.api.Facts; +import org.jeasy.rules.api.Rule; + +/** + * Basic rule implementation class that provides common methods. + * + * You can extend this class and override {@link BasicRule#evaluate(Facts)} and {@link BasicRule#execute(Facts)} to provide rule + * conditions and actions logic. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public class BasicRule implements Rule, Comparable { + + /** + * Rule name. + */ + protected String name; + + /** + * Rule description. + */ + protected String description; + + /** + * Rule priority. + */ + protected int priority; + + /** + * Create a new {@link BasicRule}. + */ + public BasicRule() { + this(Rule.DEFAULT_NAME, Rule.DEFAULT_DESCRIPTION, Rule.DEFAULT_PRIORITY); + } + + /** + * Create a new {@link BasicRule}. + * + * @param name rule name + */ + public BasicRule(final String name) { + this(name, Rule.DEFAULT_DESCRIPTION, Rule.DEFAULT_PRIORITY); + } + + /** + * Create a new {@link BasicRule}. + * + * @param name rule name + * @param description rule description + */ + public BasicRule(final String name, final String description) { + this(name, description, Rule.DEFAULT_PRIORITY); + } + + /** + * Create a new {@link BasicRule}. + * + * @param name rule name + * @param description rule description + * @param priority rule priority + */ + public BasicRule(final String name, final String description, final int priority) { + this.name = name; + this.description = description; + this.priority = priority; + } + + /** + * {@inheritDoc} + */ + public boolean evaluate(Facts facts) { + return false; + } + + /** + * {@inheritDoc} + */ + public void execute(Facts facts) throws Exception { + // no op + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public int getPriority() { + return priority; + } + + public void setPriority(final int priority) { + this.priority = priority; + } + + /* + * Rules are unique according to their names within a rules engine registry. + */ + + @Override + public boolean equals(final Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + BasicRule basicRule = (BasicRule) o; + + if (priority != basicRule.priority) + return false; + if (!name.equals(basicRule.name)) + return false; + return !(description != null ? !description.equals(basicRule.description) : basicRule.description != null); + + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + (description != null ? description.hashCode() : 0); + result = 31 * result + priority; + return result; + } + + @Override + public String toString() { + return name; + } + + @Override + public int compareTo(final Rule rule) { + if (getPriority() < rule.getPriority()) { + return -1; + } else if (getPriority() > rule.getPriority()) { + return 1; + } else { + return getName().compareTo(rule.getName()); + } + } + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/CompositeRule.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/CompositeRule.java new file mode 100644 index 0000000..4dd10d2 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/CompositeRule.java @@ -0,0 +1,141 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.api.Facts; +import org.jeasy.rules.api.Rule; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +/** + * Class representing a composite rule composed of a set of rules. + * + * A composite rule is triggered if ALL conditions of its composing rules are satisfied. + * When a composite rule is applied, actions of ALL composing rules are performed. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public class CompositeRule extends BasicRule { + + /** + * The set of composing rules. + */ + protected Set rules; + + protected Map proxyRules; + + /** + * Create a new {@link CompositeRule}. + */ + public CompositeRule() { + this(Rule.DEFAULT_NAME, Rule.DEFAULT_DESCRIPTION, Rule.DEFAULT_PRIORITY); + } + + /** + * Create a new {@link CompositeRule}. + * + * @param name rule name + */ + public CompositeRule(final String name) { + this(name, Rule.DEFAULT_DESCRIPTION, Rule.DEFAULT_PRIORITY); + } + + /** + * Create a new {@link CompositeRule}. + * + * @param name rule name + * @param description rule description + */ + public CompositeRule(final String name, final String description) { + this(name, description, Rule.DEFAULT_PRIORITY); + } + + /** + * Create a new {@link CompositeRule}. + * + * @param name rule name + * @param description rule description + * @param priority rule priority + */ + public CompositeRule(final String name, final String description, final int priority) { + super(name, description, priority); + rules = new TreeSet<>(); + proxyRules = new HashMap<>(); + } + + /** + * A composite rule is triggered if ALL conditions of all composing rules are evaluated to true. + * @return true if ALL conditions of composing rules are evaluated to true + */ + @Override + public boolean evaluate(Facts facts) { + if (!rules.isEmpty()) { + for (Rule rule : rules) { + if (!rule.evaluate(facts)) { + return false; + } + } + return true; + } + return false; + } + + /** + * When a composite rule is applied, ALL actions of composing rules are performed + * in their natural order. + * + * @throws Exception thrown if an exception occurs during actions performing + */ + @Override + public void execute(Facts facts) throws Exception { + for (Rule rule : rules) { + rule.execute(facts); + } + } + + /** + * Add a rule to the composite rule. + * @param rule the rule to add + */ + public void addRule(final Object rule) { + Rule proxy = RuleProxy.asRule(rule); + rules.add(proxy); + proxyRules.put(rule, proxy); + } + + /** + * Remove a rule from the composite rule. + * @param rule the rule to remove + */ + public void removeRule(final Object rule) { + Rule proxy = proxyRules.get(rule); + if (proxy != null) { + rules.remove(proxy); + } + } + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/DefaultRulesEngine.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/DefaultRulesEngine.java new file mode 100644 index 0000000..c751561 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/DefaultRulesEngine.java @@ -0,0 +1,220 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.api.*; + +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static java.lang.String.format; + +/** + * Default {@link RulesEngine} implementation. + * + * This implementation handles a set of rules with unique name. + * + * Rules are fired according to their natural order which is priority by default. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public final class DefaultRulesEngine implements RulesEngine { + + private static final Logger LOGGER = Logger.getLogger(RulesEngine.class.getName()); + + /** + * The engine parameters + */ + private RulesEngineParameters parameters; + + /** + * The registered rule listeners. + */ + private List ruleListeners; + + public DefaultRulesEngine() { + this.parameters = new RulesEngineParameters(); + this.ruleListeners = new ArrayList<>(); + } + + DefaultRulesEngine(final RulesEngineParameters parameters, final List ruleListeners) { + this.parameters = parameters; + this.ruleListeners = ruleListeners; + if (parameters.isSilentMode()) { + Utils.muteLoggers(); + } + } + + @Override + public RulesEngineParameters getParameters() { + return parameters; + } + + @Override + public List getRuleListeners() { + return ruleListeners; + } + + @Override + public void fire(Rules rules, Facts facts) { + if (rules.isEmpty()) { + LOGGER.warning("No rules registered! Nothing to apply"); + return; + } + sort(rules); + logEngineParameters(); + log(rules, facts); + apply(rules, facts); + } + + @Override + public Map check(Rules rules, Facts facts) { + LOGGER.info("Checking rules"); + sort(rules); + Map result = new HashMap<>(); + for (Rule rule : rules) { + if (shouldBeEvaluated(rule, facts)) { + result.put(rule, rule.evaluate(facts)); + } + } + return result; + } + + private void sort(Rules rules) { + rules.sort(); + } + + private void apply(Rules rules, Facts facts) { + + LOGGER.info("Rules evaluation started"); + for (Rule rule : rules) { + + final String name = rule.getName(); + final int priority = rule.getPriority(); + + if (priority > parameters.getPriorityThreshold()) { + LOGGER.log(Level.INFO, + "Rule priority threshold ({0}) exceeded at rule ''{1}'' with priority={2}, next rules will be skipped", + new Object[]{parameters.getPriorityThreshold(), name, priority}); + break; + } + + if (!shouldBeEvaluated(rule, facts)) { + LOGGER.log(Level.INFO, "Rule ''{0}'' has been skipped before being evaluated", name); + continue; + } + if (rule.evaluate(facts)) { + LOGGER.log(Level.INFO, "Rule ''{0}'' triggered", name); + triggerListenersAfterEvaluate(rule, true); + try { + triggerListenersBeforeExecute(rule, facts); + rule.execute(facts); + LOGGER.log(Level.INFO, "Rule ''{0}'' performed successfully", name); + triggerListenersOnSuccess(rule, facts); + + if (parameters.isSkipOnFirstAppliedRule()) { + LOGGER.info("Next rules will be skipped since parameter skipOnFirstAppliedRule is set"); + break; + } + } catch (Exception exception) { + LOGGER.log(Level.SEVERE, String.format("Rule '%s' performed with error", name), exception); + triggerListenersOnFailure(rule, exception, facts); + if (parameters.isSkipOnFirstFailedRule()) { + LOGGER.info("Next rules will be skipped since parameter skipOnFirstFailedRule is set"); + break; + } + } + } else { + LOGGER.log(Level.INFO, "Rule ''{0}'' has been evaluated to false, it has not been executed", name); + triggerListenersAfterEvaluate(rule, false); + if (parameters.isSkipOnFirstNonTriggeredRule()) { + LOGGER.info("Next rules will be skipped since parameter skipOnFirstNonTriggeredRule is set"); + break; + } + } + + } + + } + + private void triggerListenersOnFailure(final Rule rule, final Exception exception, Facts facts) { + for (RuleListener ruleListener : ruleListeners) { + ruleListener.onFailure(rule, exception, facts); + } + } + + private void triggerListenersOnSuccess(final Rule rule, Facts facts) { + for (RuleListener ruleListener : ruleListeners) { + ruleListener.onSuccess(rule, facts); + } + } + + private void triggerListenersBeforeExecute(final Rule rule, Facts facts) { + for (RuleListener ruleListener : ruleListeners) { + ruleListener.beforeExecute(rule, facts); + } + } + + private boolean triggerListenersBeforeEvaluate(Rule rule, Facts facts) { + for (RuleListener ruleListener : ruleListeners) { + if (!ruleListener.beforeEvaluate(rule, facts)) { + return false; + } + } + return true; + } + + private void triggerListenersAfterEvaluate(Rule rule, boolean evaluationResult) { + for (RuleListener ruleListener : ruleListeners) { + ruleListener.afterEvaluate(rule, evaluationResult); + } + } + + private boolean shouldBeEvaluated(Rule rule, Facts facts) { + return triggerListenersBeforeEvaluate(rule, facts); + } + + private void logEngineParameters() { + 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()); + } + + private void log(Rules rules, Facts facts) { + LOGGER.log(Level.INFO, "Registered rules:"); + for (Rule rule : rules) { + LOGGER.log(Level.INFO, format("Rule { name = '%s', description = '%s', priority = '%s'}", + rule.getName(), rule.getDescription(), rule.getPriority())); + } + + LOGGER.log(Level.INFO, "Known facts:"); + for (Map.Entry fact : facts) { + LOGGER.log(Level.INFO, format("Fact { %s : %s }", fact.getKey(), fact.getValue().toString())); + } + } + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/RuleDefinitionValidator.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/RuleDefinitionValidator.java new file mode 100644 index 0000000..fb90c64 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/RuleDefinitionValidator.java @@ -0,0 +1,161 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.annotation.*; +import org.jeasy.rules.api.Facts; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.List; + +import static java.lang.String.format; + +/** + * Validate that an annotated rule object is well defined. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +class RuleDefinitionValidator { + + void validateRuleDefinition(final Object rule) { + checkRuleClass(rule); + checkConditionMethod(rule); + checkActionMethods(rule); + checkPriorityMethod(rule); + } + + private void checkRuleClass(final Object rule) { + if (!isRuleClassWellDefined(rule)) { + throw new IllegalArgumentException(format("Rule '%s' is not annotated with '%s'", rule.getClass().getName(), Rule.class.getName())); + } + } + + private void checkConditionMethod(final Object rule) { + List conditionMethods = getMethodsAnnotatedWith(Condition.class, rule); + if (conditionMethods.isEmpty()) { + throw new IllegalArgumentException(format("Rule '%s' must have a public method annotated with '%s'", rule.getClass().getName(), Condition.class.getName())); + } + + if (conditionMethods.size() > 1) { + throw new IllegalArgumentException(format("Rule '%s' must have exactly one method annotated with '%s'", rule.getClass().getName(), Condition.class.getName())); + } + + Method conditionMethod = conditionMethods.get(0); + + if (!isConditionMethodWellDefined(conditionMethod)) { + throw new IllegalArgumentException(format("Condition method '%s' defined in rule '%s' must be public, may have parameters annotated with @Fact (and/or a parameter of type Facts) and return boolean type.", conditionMethod, rule.getClass().getName())); + } + } + + private void checkActionMethods(final Object rule) { + List actionMethods = getMethodsAnnotatedWith(Action.class, rule); + if (actionMethods.isEmpty()) { + throw new IllegalArgumentException(format("Rule '%s' must have at least one public method annotated with '%s'", rule.getClass().getName(), Action.class.getName())); + } + + for (Method actionMethod : actionMethods) { + if (!isActionMethodWellDefined(actionMethod)) { + throw new IllegalArgumentException(format("Action method '%s' defined in rule '%s' must be public and may have parameters annotated with @Fact (and/or a parameter of type Facts).", actionMethod, rule.getClass().getName())); + } + } + } + + private void checkPriorityMethod(final Object rule) { + + List priorityMethods = getMethodsAnnotatedWith(Priority.class, rule); + + if (priorityMethods.isEmpty()) { + return; + } + + if (priorityMethods.size() > 1) { + throw new IllegalArgumentException(format("Rule '%s' must have exactly one method annotated with '%s'", rule.getClass().getName(), Priority.class.getName())); + } + + Method priorityMethod = priorityMethods.get(0); + + if (!isPriorityMethodWellDefined(priorityMethod)) { + throw new IllegalArgumentException(format("Priority method '%s' defined in rule '%s' must be public, have no parameters and return integer type.", priorityMethod, rule.getClass().getName())); + } + } + + private boolean isRuleClassWellDefined(final Object rule) { + return Utils.isAnnotationPresent(Rule.class, rule.getClass()); + } + + private boolean isConditionMethodWellDefined(final Method method) { + Parameter[] parameters = method.getParameters(); + return Modifier.isPublic(method.getModifiers()) + && method.getReturnType().equals(Boolean.TYPE) + && validParameters(parameters); + } + + private boolean validParameters(Parameter[] parameters) { + List notAnnotatedParams = new ArrayList<>(); + for (Parameter parameter : parameters) { + if (parameter.getAnnotation(Fact.class) == null) { + notAnnotatedParams.add(parameter); + } + } + if (notAnnotatedParams.size() > 1) { + return false; + } else if (notAnnotatedParams.size() == 1) { + Parameter parameter = notAnnotatedParams.get(0); + return parameter.getType().isAssignableFrom(Facts.class); + } + return true; + } + + private boolean isActionMethodWellDefined(final Method method) { + Parameter[] parameters = method.getParameters(); + return Modifier.isPublic(method.getModifiers()) + && validParameters(parameters); + } + + private boolean isPriorityMethodWellDefined(final Method method) { + return Modifier.isPublic(method.getModifiers()) + && method.getReturnType().equals(Integer.TYPE) + && method.getParameterTypes().length == 0; + } + + private List getMethodsAnnotatedWith(final Class annotation, final Object rule) { + Method[] methods = getMethods(rule); + List annotatedMethods = new ArrayList<>(); + for (Method method : methods) { + if (method.isAnnotationPresent(annotation)) { + annotatedMethods.add(method); + } + } + return annotatedMethods; + } + + private Method[] getMethods(final Object rule) { + return rule.getClass().getMethods(); + } + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java new file mode 100644 index 0000000..6793617 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/RuleProxy.java @@ -0,0 +1,245 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.annotation.Fact; +import org.jeasy.rules.api.Facts; +import org.jeasy.rules.annotation.Action; +import org.jeasy.rules.annotation.Condition; +import org.jeasy.rules.annotation.Priority; +import org.jeasy.rules.api.Rule; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.lang.reflect.Proxy; +import java.util.*; +import java.util.logging.Logger; + +public class RuleProxy implements InvocationHandler { + + private static final Logger LOGGER = Logger.getLogger(RuleProxy.class.getName()); + + private Object target; + + private static RuleDefinitionValidator ruleDefinitionValidator = new RuleDefinitionValidator(); + + private RuleProxy(final Object target) { + this.target = target; + } + + /** + * Makes the rule object implement the {@link Rule} interface. + * + * @param rule the annotated rule object. + * @return a proxy that implements the {@link Rule} interface. + */ + public static Rule asRule(final Object rule) { + Rule result; + if (Utils.getInterfaces(rule).contains(Rule.class)) { + result = (Rule) rule; + } else { + ruleDefinitionValidator.validateRuleDefinition(rule); + result = (Rule) Proxy.newProxyInstance( + Rule.class.getClassLoader(), + new Class[]{Rule.class, Comparable.class}, + new RuleProxy(rule)); + } + return result; + } + + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { + String methodName = method.getName(); + if (methodName.equals("getName")) { + return getRuleName(); + } + if (methodName.equals("getDescription")) { + return getRuleDescription(); + } + if (methodName.equals("getPriority")) { + return getRulePriority(); + } + if (methodName.equals("evaluate")) { + Facts facts = (Facts) args[0]; + Method conditionMethod = getConditionMethod(); + List actualParameters = getActualParameters(conditionMethod, facts); + return conditionMethod.invoke(target, actualParameters.toArray()); // validated upfront + } + if (methodName.equals("execute")) { + for (ActionMethodOrderBean actionMethodBean : getActionMethodBeans()) { + Facts facts = (Facts) args[0]; + Method actiomMethod = actionMethodBean.getMethod(); + List actualParameters = getActualParameters(actiomMethod, facts); + actiomMethod.invoke(target, actualParameters.toArray()); + } + } + if (methodName.equals("equals")) { + return target.equals(args[0]); + } + if (methodName.equals("hashCode")) { + return target.hashCode(); + } + if (methodName.equals("toString")) { + return target.toString(); + } + if (methodName.equals("compareTo")) { + Method compareToMethod = getCompareToMethod(); + if (compareToMethod != null) { + return compareToMethod.invoke(target, args); + } else { + Rule otherRule = (Rule) args[0]; + return compareTo(otherRule); + } + } + return null; + } + + private List getActualParameters(Method method, Facts facts) { + Parameter[] parameters = method.getParameters(); // validated upfront + List actualParameters = new ArrayList<>(); + for (Parameter parameter : parameters) { + Fact annotation = parameter.getAnnotation(Fact.class); // validated upfront + if (annotation == null) { // validated upfront, there may be only one parameter not annotated and which is of type Facts.class + actualParameters.add(facts); + } else { + String factName = annotation.value(); + Object fact = facts.get(factName); + if (fact == null) { + throw new RuntimeException(String.format("No fact named %s found in known facts", factName)); + } + actualParameters.add(fact); + } + } + return actualParameters; + } + + private int compareTo(final Rule otherRule) throws Exception { + String otherName = otherRule.getName(); + int otherPriority = otherRule.getPriority(); + String name = getRuleName(); + int priority = getRulePriority(); + + if (priority < otherPriority) { + return -1; + } else if (priority > otherPriority) { + return 1; + } else { + return name.compareTo(otherName); + } + } + + private int getRulePriority() throws Exception { + int priority = Rule.DEFAULT_PRIORITY; + + Method[] methods = getMethods(); + for (Method method : methods) { + if (method.isAnnotationPresent(Priority.class)) { + priority = (Integer) method.invoke(target); + break; + } + } + return priority; + } + + private Method getConditionMethod() { + Method[] methods = getMethods(); + for (Method method : methods) { + if (method.isAnnotationPresent(Condition.class)) { + return method; + } + } + return null; + } + + private Set getActionMethodBeans() { + Method[] methods = getMethods(); + Set actionMethodBeans = new TreeSet<>(); + for (Method method : methods) { + if (method.isAnnotationPresent(Action.class)) { + Action actionAnnotation = method.getAnnotation(Action.class); + int order = actionAnnotation.order(); + actionMethodBeans.add(new ActionMethodOrderBean(method, order)); + } + } + return actionMethodBeans; + } + + private Method getCompareToMethod() { + Method[] methods = getMethods(); + for (Method method : methods) { + if (method.getName().equals("compareTo")) { + return method; + } + } + return null; + } + + private Method[] getMethods() { + return getTargetClass().getMethods(); + } + + private org.jeasy.rules.annotation.Rule getRuleAnnotation() { + return Utils.findAnnotation(org.jeasy.rules.annotation.Rule.class, getTargetClass()); + } + + private String getRuleName() { + org.jeasy.rules.annotation.Rule rule = getRuleAnnotation(); + return rule.name().equals(Rule.DEFAULT_NAME) ? getTargetClass().getSimpleName() : rule.name(); + } + + private String getRuleDescription() { + // Default description = "when " + conditionMethodName + " then " + comma separated actionMethodsNames + StringBuilder description = new StringBuilder(); + appendConditionMethodName(description); + appendActionMethodsNames(description); + + org.jeasy.rules.annotation.Rule rule = getRuleAnnotation(); + return rule.description().equals(Rule.DEFAULT_DESCRIPTION) ? description.toString() : rule.description(); + } + + private void appendConditionMethodName(StringBuilder description) { + Method method = getConditionMethod(); + if (method != null) { + description.append("when "); + description.append(method.getName()); + description.append(" then "); + } + } + + private void appendActionMethodsNames(StringBuilder description) { + Iterator iterator = getActionMethodBeans().iterator(); + while (iterator.hasNext()) { + description.append(iterator.next().getMethod().getName()); + if (iterator.hasNext()) { + description.append(","); + } + } + } + + private Class getTargetClass() { + return target.getClass(); + } + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/RulesEngineBuilder.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/RulesEngineBuilder.java new file mode 100644 index 0000000..da2bc4c --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/RulesEngineBuilder.java @@ -0,0 +1,91 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.api.RuleListener; +import org.jeasy.rules.api.RulesEngine; + +import java.util.ArrayList; +import java.util.List; + +/** + * Builder for rules engine instances. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public class RulesEngineBuilder { + + private RulesEngineParameters parameters; + + private List ruleListeners; + + public static RulesEngineBuilder aNewRulesEngine() { + return new RulesEngineBuilder(); + } + + private RulesEngineBuilder() { + parameters = new RulesEngineParameters(RulesEngine.DEFAULT_NAME, false, false, RulesEngine.DEFAULT_RULE_PRIORITY_THRESHOLD, false); + ruleListeners = new ArrayList<>(); + } + + public RulesEngineBuilder named(final String name) { + parameters.setName(name); + return this; + } + + public RulesEngineBuilder withSkipOnFirstAppliedRule(final boolean skipOnFirstAppliedRule) { + parameters.setSkipOnFirstAppliedRule(skipOnFirstAppliedRule); + return this; + } + + public RulesEngineBuilder withSkipOnFirstNonTriggeredRule(final boolean skipOnFirstNonTriggeredRule) { + parameters.setSkipOnFirstNonTriggeredRule(skipOnFirstNonTriggeredRule); + return this; + } + + public RulesEngineBuilder withSkipOnFirstFailedRule(final boolean skipOnFirstFailedRule) { + parameters.setSkipOnFirstFailedRule(skipOnFirstFailedRule); + return this; + } + + public RulesEngineBuilder withRulePriorityThreshold(final int priorityThreshold) { + parameters.setPriorityThreshold(priorityThreshold); + return this; + } + + public RulesEngineBuilder withRuleListener(final RuleListener ruleListener) { + this.ruleListeners.add(ruleListener); + return this; + } + + public RulesEngineBuilder withSilentMode(final boolean silentMode) { + parameters.setSilentMode(silentMode); + return this; + } + + public RulesEngine build() { + return new DefaultRulesEngine(parameters, ruleListeners); + } + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/RulesEngineParameters.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/RulesEngineParameters.java new file mode 100644 index 0000000..ab523a3 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/RulesEngineParameters.java @@ -0,0 +1,125 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.api.RulesEngine; + +/** + * Parameters of the rules engine. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public class RulesEngineParameters { + + /** + * The engine name. + */ + protected String name; + + /** + * Parameter to skip next applicable rules when a rule is applied. + */ + 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. + */ + private boolean skipOnFirstFailedRule; + + /** + * Parameter to skip next rules if priority exceeds a user defined threshold. + */ + private int priorityThreshold; + + /** + * Parameter to mute loggers. + */ + private boolean silentMode; + + public RulesEngineParameters() { + this.name = RulesEngine.DEFAULT_NAME; + this.priorityThreshold = RulesEngine.DEFAULT_RULE_PRIORITY_THRESHOLD; + } + + public RulesEngineParameters(String name, boolean skipOnFirstAppliedRule, boolean skipOnFirstFailedRule, int priorityThreshold, boolean silentMode) { + this.name = name; + this.skipOnFirstAppliedRule = skipOnFirstAppliedRule; + this.skipOnFirstFailedRule = skipOnFirstFailedRule; + this.priorityThreshold = priorityThreshold; + this.silentMode = silentMode; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getPriorityThreshold() { + return priorityThreshold; + } + + public void setPriorityThreshold(int priorityThreshold) { + this.priorityThreshold = priorityThreshold; + } + + public boolean isSilentMode() { + return silentMode; + } + + public void setSilentMode(boolean silentMode) { + this.silentMode = silentMode; + } + + public boolean isSkipOnFirstAppliedRule() { + return skipOnFirstAppliedRule; + } + + public void setSkipOnFirstAppliedRule(boolean skipOnFirstAppliedRule) { + this.skipOnFirstAppliedRule = skipOnFirstAppliedRule; + } + + public boolean isSkipOnFirstNonTriggeredRule() { + return skipOnFirstNonTriggeredRule; + } + + public void setSkipOnFirstNonTriggeredRule(boolean skipOnFirstNonTriggeredRule) { + this.skipOnFirstNonTriggeredRule = skipOnFirstNonTriggeredRule; + } + + public boolean isSkipOnFirstFailedRule() { + return skipOnFirstFailedRule; + } + + public void setSkipOnFirstFailedRule(boolean skipOnFirstFailedRule) { + this.skipOnFirstFailedRule = skipOnFirstFailedRule; + } +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/Utils.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/Utils.java new file mode 100644 index 0000000..d8f849a --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/Utils.java @@ -0,0 +1,109 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; + +import static java.util.Arrays.asList; + +/** + * Utilities class. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +final class Utils { + + private static final Logger LOGGER = Logger.getLogger(Utils.class.getName()); + + static { + try { + if (System.getProperty("java.util.logging.config.file") == null && + System.getProperty("java.util.logging.config.class") == null) { + LogManager.getLogManager().readConfiguration(Utils.class.getResourceAsStream("/logging.properties")); + } + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Unable to load logging configuration file", e); + } + } + + private Utils() { + + } + + static void muteLoggers() { + Enumeration loggerNames = LogManager.getLogManager().getLoggerNames(); + while (loggerNames.hasMoreElements()) { + String loggerName = loggerNames.nextElement(); + if (loggerName.startsWith("org.easyrules")) { + muteLogger(loggerName); + } + } + } + + private static void muteLogger(final String logger) { + Logger.getLogger(logger).setUseParentHandlers(false); + Handler[] handlers = Logger.getLogger(logger).getHandlers(); + for (Handler handler : handlers) { + Logger.getLogger(logger).removeHandler(handler); + } + } + + static List> getInterfaces(final Object rule) { + List> interfaces = new ArrayList<>(); + Class clazz = rule.getClass(); + while (clazz.getSuperclass() != null) { + interfaces.addAll(asList(clazz.getInterfaces())); + clazz = clazz.getSuperclass(); + } + return interfaces; + } + + static A findAnnotation(final Class targetAnnotation, final Class annotatedType) { + + A foundAnnotation = annotatedType.getAnnotation(targetAnnotation); + if (foundAnnotation == null) { + for (Annotation annotation : annotatedType.getAnnotations()) { + Class annotationType = annotation.annotationType(); + if (annotationType.isAnnotationPresent(targetAnnotation)) { + foundAnnotation = annotationType.getAnnotation(targetAnnotation); + break; + } + } + } + return foundAnnotation; + } + + static boolean isAnnotationPresent(final Class targetAnnotation, final Class annotatedType) { + return findAnnotation(targetAnnotation, annotatedType) != null; + } + +} diff --git a/easy-rules-core/src/main/java/org/jeasy/rules/core/package-info.java b/easy-rules-core/src/main/java/org/jeasy/rules/core/package-info.java new file mode 100644 index 0000000..2a5a3e2 --- /dev/null +++ b/easy-rules-core/src/main/java/org/jeasy/rules/core/package-info.java @@ -0,0 +1,27 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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. + */ +/** + * This package contains Easy Rules core implementation. + */ +package org.jeasy.rules.core; diff --git a/easyrules-core/src/main/resources/logging.properties b/easy-rules-core/src/main/resources/logging.properties similarity index 100% rename from easyrules-core/src/main/resources/logging.properties rename to easy-rules-core/src/main/resources/logging.properties diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/EasyRulesTestSuite.java b/easy-rules-core/src/test/java/org/jeasy/rules/EasyRulesTestSuite.java new file mode 100644 index 0000000..870eb63 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/EasyRulesTestSuite.java @@ -0,0 +1,54 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules; + +import junit.framework.TestSuite; +import org.jeasy.rules.core.*; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Test suite for Easy Rules core module. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ + AnnotationInheritanceTest.class, + BasicRuleTest.class, + RulePriorityThresholdTest.class, + SkipOnFirstAppliedRuleTest.class, + SkipOnFirstFailedRuleTest.class, + SkipOnFirstNonTriggeredRuleTest.class, + RuleListenerTest.class, + CustomRuleOrderingTest.class, + RuleProxyTest.class, + RulesEngineBuilderTest.class, + CompositeRuleTest.class, + RuleDefinitionValidatorTest.class, + DefaultRulesEngineTest.class, + UtilsTest.class}) +public class EasyRulesTestSuite extends TestSuite { + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithActionMethodHavingOneArgumentNotOfTypeFacts.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithActionMethodHavingOneArgumentNotOfTypeFacts.java new file mode 100644 index 0000000..6763a73 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithActionMethodHavingOneArgumentNotOfTypeFacts.java @@ -0,0 +1,47 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithActionMethodHavingOneArgumentNotOfTypeFacts { + + private boolean executed; + + @Condition + public boolean when() { + return true; + } + + @Action + public void then(int i) throws Exception { + if (i == 1) { + executed = true; + } + } + + public boolean isExecuted() { + return executed; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithConditionMethodHavingNonBooleanReturnType.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithConditionMethodHavingNonBooleanReturnType.java new file mode 100644 index 0000000..46b16d0 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithConditionMethodHavingNonBooleanReturnType.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithConditionMethodHavingNonBooleanReturnType { + + private boolean executed; + + @Condition + public int when() { + return 0; + } + + @Action + public void then() throws Exception { + executed = true; + } + + public boolean isExecuted() { + return executed; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithConditionMethodHavingOneArgumentNotOfTypeFacts.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithConditionMethodHavingOneArgumentNotOfTypeFacts.java new file mode 100644 index 0000000..fc92195 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithConditionMethodHavingOneArgumentNotOfTypeFacts.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithConditionMethodHavingOneArgumentNotOfTypeFacts { + + private boolean executed; + + @Condition + public boolean when(int i) { + return i == 0; + } + + @Action + public void then() throws Exception { + executed = true; + } + + public boolean isExecuted() { + return executed; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithMetaRuleAnnotation.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithMetaRuleAnnotation.java new file mode 100644 index 0000000..df34ffc --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithMetaRuleAnnotation.java @@ -0,0 +1,37 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@MetaRule +public class AnnotatedRuleWithMetaRuleAnnotation { + + @Condition + public boolean when() { + return true; + } + + @Action + public void then() throws Exception { + } +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithMoreThanOnePriorityMethod.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithMoreThanOnePriorityMethod.java new file mode 100644 index 0000000..72e765a --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithMoreThanOnePriorityMethod.java @@ -0,0 +1,55 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithMoreThanOnePriorityMethod { + + private boolean executed; + + @Condition + public boolean when() { + return true; + } + + @Action + public void then() throws Exception { + executed = true; + } + + @Priority + public int getPriority() { + return 0; + } + + @Priority + public int getRulePriority() { + return 1; + } + + public boolean isExecuted() { + return executed; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicActionMethod.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicActionMethod.java new file mode 100644 index 0000000..5b55868 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicActionMethod.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithNotPublicActionMethod { + + private boolean executed; + + @Condition + private boolean when() { + return true; + } + + @Action + private void then() throws Exception { + executed = true; + } + + public boolean isExecuted() { + return executed; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicConditionMethod.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicConditionMethod.java new file mode 100644 index 0000000..b71012a --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicConditionMethod.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithNotPublicConditionMethod { + + private boolean executed; + + @Condition + private boolean when() { + return true; + } + + @Action + public void then() throws Exception { + executed = true; + } + + public boolean isExecuted() { + return executed; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicPriorityMethod.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicPriorityMethod.java new file mode 100644 index 0000000..adeccb9 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithNotPublicPriorityMethod.java @@ -0,0 +1,50 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithNotPublicPriorityMethod { + + private boolean executed; + + @Condition + private boolean when() { + return true; + } + + @Action + private void then() throws Exception { + executed = true; + } + + public boolean isExecuted() { + return executed; + } + + @Priority + private int getPriority() { + return 1; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithPriorityMethodHavingArguments.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithPriorityMethodHavingArguments.java new file mode 100644 index 0000000..18cad0c --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithPriorityMethodHavingArguments.java @@ -0,0 +1,50 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithPriorityMethodHavingArguments { + + private boolean executed; + + @Condition + private boolean when() { + return true; + } + + @Action + private void then() throws Exception { + executed = true; + } + + public boolean isExecuted() { + return executed; + } + + @Priority + public int getPriority(int i) { + return i; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithPriorityMethodHavingNonIntegerReturnType.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithPriorityMethodHavingNonIntegerReturnType.java new file mode 100644 index 0000000..f674f32 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithPriorityMethodHavingNonIntegerReturnType.java @@ -0,0 +1,50 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithPriorityMethodHavingNonIntegerReturnType { + + private boolean executed; + + @Condition + private boolean when() { + return true; + } + + @Action + private void then() throws Exception { + executed = true; + } + + public boolean isExecuted() { + return executed; + } + + @Priority + public String getPriority() { + return "1"; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithoutActionMethod.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithoutActionMethod.java new file mode 100644 index 0000000..e9cee14 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithoutActionMethod.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithoutActionMethod { + + private boolean executed; + + @Condition + public boolean when() { + return true; + } + + public void then() throws Exception { + executed = true; + } + + public boolean isExecuted() { + return executed; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithoutCondition.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithoutCondition.java new file mode 100644 index 0000000..b5f380d --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/AnnotatedRuleWithoutCondition.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +@Rule +public class AnnotatedRuleWithoutCondition { + + private boolean executed; + + public boolean when() { + return true; + } + + @Action + public void then() throws Exception { + executed = true; + } + + public boolean isExecuted() { + return executed; + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/annotation/MetaRule.java b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/MetaRule.java new file mode 100644 index 0000000..702b513 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/annotation/MetaRule.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Rule +public @interface MetaRule { +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/AbstractTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/AbstractTest.java new file mode 100644 index 0000000..dc96d7c --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/AbstractTest.java @@ -0,0 +1,58 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.api.Facts; +import org.jeasy.rules.api.Rule; +import org.jeasy.rules.api.Rules; +import org.jeasy.rules.api.RulesEngine; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public abstract class AbstractTest { + + @Mock + protected Rule rule1, rule2; + @Mock + protected Object fact1, fact2; + + protected Facts facts; + protected Rules rules; + + protected RulesEngine rulesEngine; + + @Before + public void setup() throws Exception { + facts = new Facts(); + facts.add("fact1", fact1); + facts.add("fact2", fact2); + rules = new Rules(rule1, rule2); + + rulesEngine = RulesEngineBuilder.aNewRulesEngine().build(); + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotatedRulesTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotatedRulesTest.java new file mode 100644 index 0000000..a2f676c --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotatedRulesTest.java @@ -0,0 +1,83 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.annotation.Action; +import org.jeasy.rules.annotation.Condition; +import org.jeasy.rules.annotation.Fact; +import org.jeasy.rules.annotation.Rule; +import org.jeasy.rules.api.Facts; +import org.jeasy.rules.api.Rules; +import org.jeasy.rules.api.RulesEngine; +import org.junit.Test; + +public class AnnotatedRulesTest { + + @Test + public void test() throws Exception { + Facts facts = new Facts(); + facts.add("rain", true); + facts.add("age", 18); + + Rules rules = new Rules( + new WeatherRule(), + new AgeRule() + ); + + RulesEngine rulesEngine = new DefaultRulesEngine(); + + rulesEngine.fire(rules, facts); + } + + @Rule + class AgeRule { + + @Condition + public boolean isAdult(@Fact("age") int age) { + return age >= 18; + } + + @Action + public void then() { + System.out.println("You are an adult"); + } + + } + + + @Rule + class WeatherRule { + + @Condition + public boolean itRains(@Fact("rain") boolean rain) { + return rain; + } + + @Action + public void takeAnUmbrella(Facts facts) { + System.out.println("It rains, take an umbrella!"); + } + + } +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotationInheritanceTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotationInheritanceTest.java new file mode 100644 index 0000000..0be71ea --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/AnnotationInheritanceTest.java @@ -0,0 +1,68 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.annotation.Action; +import org.jeasy.rules.annotation.Condition; +import org.jeasy.rules.api.Facts; +import org.jeasy.rules.api.Rules; +import org.jeasy.rules.api.RulesEngine; +import org.jeasy.rules.annotation.Rule; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AnnotationInheritanceTest { + + @Test + public void annotationsShouldBeInherited() throws Exception { + MyChildRule myChildRule = new MyChildRule(); + RulesEngine rulesEngine = RulesEngineBuilder.aNewRulesEngine().build(); + Rules rules = new Rules(); + rules.register(myChildRule); + rulesEngine.fire(rules, new Facts()); + + assertThat(myChildRule.isExecuted()).isTrue(); + } + + @Rule + class MyBaseRule { + protected boolean executed; + @Condition + public boolean when() { + return true; + } + @Action + public void then() { + executed = true; + } + public boolean isExecuted() { + return executed; + } + } + + class MyChildRule extends MyBaseRule { + + } +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/BasicRuleTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/BasicRuleTest.java new file mode 100644 index 0000000..a184dca --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/BasicRuleTest.java @@ -0,0 +1,112 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.api.Facts; +import org.jeasy.rules.api.Rules; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BasicRuleTest extends AbstractTest { + + @Test + public void basicRuleEvaluateShouldReturnFalse() throws Exception { + BasicRule basicRule = new BasicRule(); + assertThat(basicRule.evaluate(facts)).isFalse(); + } + + @Test + public void testCompareTo() { + FirstRule rule1 = new FirstRule(); + FirstRule rule2 = new FirstRule(); + + assertThat(rule1.compareTo(rule2)).isEqualTo(0); + assertThat(rule2.compareTo(rule1)).isEqualTo(0); + } + + @Test + public void testSortSequence() { + FirstRule rule1 = new FirstRule(); + SecondRule rule2 = new SecondRule(); + ThirdRule rule3 = new ThirdRule(); + + rules = new Rules(rule1, rule2, rule3); + + rulesEngine.check(rules, facts); + assertThat(rules).containsSequence(rule1, rule3, rule2); + } + + class FirstRule extends BasicRule { + @Override + public int getPriority() { + return 1; + } + + @Override + public boolean evaluate(Facts facts) { + return true; + } + + @Override + public String getName() { + return "rule1"; + } + } + + class SecondRule extends BasicRule { + @Override + public int getPriority() { + return 3; + } + + @Override + public boolean evaluate(Facts facts) { + return true; + } + + @Override + public String getName() { + return "rule2"; + } + } + + class ThirdRule extends BasicRule { + @Override + public int getPriority() { + return 2; + } + + @Override + public boolean evaluate(Facts facts) { + return true; + } + + @Override + public String getName() { + return "rule3"; + } + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/CompositeRuleTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/CompositeRuleTest.java new file mode 100644 index 0000000..a0b94f3 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/CompositeRuleTest.java @@ -0,0 +1,171 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.annotation.Action; +import org.jeasy.rules.annotation.Condition; +import org.jeasy.rules.annotation.Rule; +import org.junit.Before; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +/** + * Test class for composite rule execution. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public class CompositeRuleTest extends AbstractTest { + + private CompositeRule compositeRule; + + @Before + public void setup() throws Exception { + super.setup(); + when(rule1.evaluate(facts)).thenReturn(true); + when(rule2.evaluate(facts)).thenReturn(true); + when(rule2.compareTo(rule1)).thenReturn(1); + compositeRule = new CompositeRule(); + } + + @Test + public void compositeRuleAndComposingRulesMustBeExecuted() throws Exception { + compositeRule.addRule(rule1); + compositeRule.addRule(rule2); + rules.clear(); // FIXME + rules.register(compositeRule); + rulesEngine.fire(rules, facts); + verify(rule1).execute(facts); + verify(rule2).execute(facts); + } + + @Test + public void compositeRuleMustNotBeExecutedIfAComposingRuleEvaluatesToFalse() throws Exception { + when(rule2.evaluate(facts)).thenReturn(false); + compositeRule.addRule(rule1); + compositeRule.addRule(rule2); + rules.clear(); // FIXME + rules.register(compositeRule); + rulesEngine.fire(rules, facts); + + /* + * The composing rules should not be executed + * since not all rules conditions evaluate to TRUE + */ + + //Rule 1 should not be executed + verify(rule1, never()).execute(facts); + + //Rule 2 should not be executed + verify(rule2, never()).execute(facts); + + } + + @Test + public void whenARuleIsRemoved_thenItShouldNotBeEvaluated() throws Exception { + + compositeRule.addRule(rule1); + compositeRule.addRule(rule2); + compositeRule.removeRule(rule2); + + rules.clear(); // FIXME + rules.register(compositeRule); + + rulesEngine.fire(rules, facts); + + //Rule 1 should be executed + verify(rule1).execute(facts); + + //Rule 2 should not be evaluated nor executed + verify(rule2, never()).evaluate(facts); + verify(rule2, never()).execute(facts); + + } + + @Test + public void whenNoComposingRulesAreRegistered_thenCompositeRuleShouldEvaluateToFalse() { + assertThat(compositeRule.evaluate(facts)).isFalse(); + } + + @Test + public void testCompositeRuleWithAnnotatedComposingRules() throws Exception { + MyRule rule = new MyRule(); + compositeRule = new CompositeRule("myCompositeRule"); + compositeRule.addRule(rule); + + rules.register(compositeRule);; + rulesEngine.fire(rules, facts); + + assertThat(rule.isExecuted()).isTrue(); + } + + @Test + public void whenAnnotatedRuleIsRemoved_thenItsProxyShouldBeRetrieved() throws Exception { + MyRule rule = new MyRule(); + MyAnnotatedRule annotatedRule = new MyAnnotatedRule(); + compositeRule = new CompositeRule("myCompositeRule", "composite rule with mixed types of rules"); + compositeRule.addRule(rule); + compositeRule.addRule(annotatedRule); + compositeRule.removeRule(annotatedRule); + + rules.register(compositeRule); + rulesEngine.fire(rules, facts); + + assertThat(rule.isExecuted()).isTrue(); + assertThat(annotatedRule.isExecuted()).isFalse(); + } + + @Rule + class MyRule { + boolean executed; + @Condition + public boolean when() { + return true; + } + @Action + public void then() { + executed = true; + } + public boolean isExecuted() { + return executed; + } + } + + @Rule + static class MyAnnotatedRule { + private boolean executed; + @Condition + public boolean evaluate() { + return true; + } + @Action + public void execute() { + executed = true; + } + public boolean isExecuted() { + return executed; + } + } +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/CustomRuleOrderingTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/CustomRuleOrderingTest.java new file mode 100644 index 0000000..79ec23a --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/CustomRuleOrderingTest.java @@ -0,0 +1,84 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.api.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.when; + +/** + * Test class for custom rule ordering. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +@RunWith(MockitoJUnitRunner.class) +public class CustomRuleOrderingTest extends AbstractTest { + + @Mock + private MyRule rule1, rule2; + + @Test + public void whenCompareToIsOverridden_thenShouldExecuteRulesInTheCustomOrder() throws Exception { + + when(rule1.getName()).thenReturn("a"); + when(rule1.getPriority()).thenReturn(1); + when(rule1.evaluate(facts)).thenReturn(true); + + when(rule2.getName()).thenReturn("b"); + when(rule2.getPriority()).thenReturn(0); + when(rule2.evaluate(facts)).thenReturn(true); + + when(rule2.compareTo(rule1)).thenCallRealMethod(); + + rules.clear(); + rules.register(rule1); + rules.register(rule2); + + rulesEngine.fire(rules, facts); + + /* + * By default, if compareTo is not overridden, then rule2 should be executed first (priority 0 < 1). + * But in this case, the compareTo method order rules by their name, so rule1 should be executed first ("a" < "b") + */ + InOrder inOrder = inOrder(rule1, rule2); + inOrder.verify(rule1).execute(facts); + inOrder.verify(rule2).execute(facts); + + } + + class MyRule extends BasicRule { + + @Override + public int compareTo(Rule rule) { + return getName().compareTo(rule.getName()); + } + + } +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/DefaultRulesEngineTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/DefaultRulesEngineTest.java new file mode 100644 index 0000000..b3c40eb --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/DefaultRulesEngineTest.java @@ -0,0 +1,266 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.annotation.Action; +import org.jeasy.rules.annotation.Condition; +import org.jeasy.rules.annotation.Priority; +import org.jeasy.rules.api.RuleListener; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.*; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; + +/** + * Test class for {@link DefaultRulesEngine}. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public class DefaultRulesEngineTest extends AbstractTest { + + @Mock + private BasicRule rule, anotherRule; + + @Mock + private RuleListener ruleListener; + + private AnnotatedRule annotatedRule; + + @Before + public void setup() throws Exception { + super.setup(); + when(rule.getName()).thenReturn("r"); + when(rule.getDescription()).thenReturn("d"); + when(rule.getPriority()).thenReturn(1); + annotatedRule = new AnnotatedRule(); + } + + @Test + public void whenConditionIsTrue_thenActionShouldBeExecuted() throws Exception { + when(rule.evaluate(facts)).thenReturn(true); + + rules.clear();// FIXME + rules.register(rule); + + rulesEngine.fire(rules, facts); + + verify(rule).execute(facts); + } + + @Test + public void whenConditionIsFalse_thenActionShouldNotBeExecuted() throws Exception { + when(rule.evaluate(facts)).thenReturn(false); + rules.clear();// FIXME + rules.register(rule); + + rulesEngine.fire(rules, facts); + + verify(rule, never()).execute(facts); + } + + @Test + public void rulesMustBeTriggeredInTheirNaturalOrder() throws Exception { + when(rule.evaluate(facts)).thenReturn(true); + when(anotherRule.evaluate(facts)).thenReturn(true); + when(anotherRule.compareTo(rule)).thenReturn(1); + rules.clear();// FIXME + rules.register(rule); + rules.register(anotherRule); + + rulesEngine.fire(rules, facts); + + InOrder inOrder = inOrder(rule, anotherRule); + inOrder.verify(rule).execute(facts); + inOrder.verify(anotherRule).execute(facts); + } + + @Test + public void rulesMustBeCheckedInTheirNaturalOrder() throws Exception { + when(rule.evaluate(facts)).thenReturn(true); + when(anotherRule.evaluate(facts)).thenReturn(true); + when(anotherRule.compareTo(rule)).thenReturn(1); + rules.clear();// FIXME + rules.register(rule); + rules.register(anotherRule); + + rulesEngine.check(rules, facts); + + InOrder inOrder = inOrder(rule, anotherRule); + inOrder.verify(rule).evaluate(facts); + inOrder.verify(anotherRule).evaluate(facts); + } + + @Test + public void actionsMustBeExecutedInTheDefinedOrder() { + rules.clear(); // FIXME + rules.register(annotatedRule); + rulesEngine.fire(rules, facts); + assertEquals("012", annotatedRule.getActionSequence()); + } + + @Test + public void annotatedRulesAndNonAnnotatedRulesShouldBeUsableTogether() throws Exception { + when(rule.evaluate(facts)).thenReturn(true); + rules.clear(); // FIXME + rules.register(rule); + rules.register(annotatedRule); + + rulesEngine.fire(rules, facts); + + verify(rule).execute(facts); + assertThat(annotatedRule.isExecuted()).isTrue(); + } + + @Test + public void whenRuleNameIsNotSpecified_thenItShouldBeEqualToClassNameByDefault() throws Exception { + org.jeasy.rules.api.Rule rule = RuleProxy.asRule(new DummyRule()); + assertThat(rule.getName()).isEqualTo("DummyRule"); + } + + @Test + public void whenRuleDescriptionIsNotSpecified_thenItShouldBeEqualToConditionNameFollowedByActionsNames() throws Exception { + org.jeasy.rules.api.Rule rule = RuleProxy.asRule(new DummyRule()); + assertThat(rule.getDescription()).isEqualTo("when condition then action1,action2"); + } + + @Test + public void testCheckRules() throws Exception { + // Given + when(rule.evaluate(facts)).thenReturn(true); + rules.clear(); // FIXME + rules.register(rule); + rules.register(annotatedRule); + + // When + Map result = rulesEngine.check(rules, facts); + + // Then + assertThat(result).hasSize(2); + for (org.jeasy.rules.api.Rule r : rules) { + assertThat(result.get(r)).isTrue(); + } + } + + @Test + public void listenerShouldBeInvokedBeforeCheckingRules() throws Exception { + // Given + when(rule.evaluate(facts)).thenReturn(true); + when(ruleListener.beforeEvaluate(rule, facts)).thenReturn(true); + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withRuleListener(ruleListener) + .build(); + rules.clear(); // FIXME + rules.register(rule); + + // When + rulesEngine.check(rules, facts); + + // Then + verify(ruleListener).beforeEvaluate(rule, facts); + } + + @Test + public void testGetRuleListeners() throws Exception { + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withRuleListener(ruleListener) + .build(); + + assertThat(rulesEngine.getRuleListeners()) + .containsExactly(ruleListener); + } + + @After + public void clearRules() { + rules.clear(); + } + + @org.jeasy.rules.annotation.Rule(name = "myRule", description = "my rule description") + public class AnnotatedRule { + + private boolean executed; + + private String actionSequence = ""; + + @Condition + public boolean when() { + return true; + } + + @Action + public void then0() throws Exception { + actionSequence += "0"; + } + + @Action(order = 1) + public void then1() throws Exception { + actionSequence += "1"; + } + + @Action(order = 2) + public void then2() throws Exception { + actionSequence += "2"; + executed = true; + } + + @Priority + public int getPriority() { + return 0; + } + + public boolean isExecuted() { + return executed; + } + + public String getActionSequence() { + return actionSequence; + } + + } + + @org.jeasy.rules.annotation.Rule + public class DummyRule { + + @Condition + public boolean condition() { + return true; + } + + @Action(order = 1) + public void action1() throws Exception { + // no op + } + + @Action(order = 2) + public void action2() throws Exception { + // no op + } + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/RuleDefinitionValidatorTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/RuleDefinitionValidatorTest.java new file mode 100644 index 0000000..d1b6d14 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/RuleDefinitionValidatorTest.java @@ -0,0 +1,117 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + + +import org.jeasy.rules.annotation.*; +import org.junit.Before; +import org.junit.Test; + +public class RuleDefinitionValidatorTest { + + private RuleDefinitionValidator ruleDefinitionValidator; + + @Before + public void setup(){ + ruleDefinitionValidator = new RuleDefinitionValidator(); + } + + /* + * Rule annotation test + */ + @Test(expected = IllegalArgumentException.class) + public void notAnnotatedRuleMustNotBeAccepted() { + ruleDefinitionValidator.validateRuleDefinition(new Object()); + } + + @Test + public void withCustomAnnotationThatIsItselfAnnotatedWithTheRuleAnnotation() throws Throwable { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithMetaRuleAnnotation()); + } + + /* + * Conditions methods tests + */ + @Test(expected = IllegalArgumentException.class) + public void conditionMethodMustBeDefined() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithoutCondition()); + } + + @Test(expected = IllegalArgumentException.class) + public void conditionMethodMustBePublic() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithNotPublicConditionMethod()); + } + + @Test(expected = IllegalArgumentException.class) + public void whenConditionMethodHasOneNonAnnotatedParameter_thenThisParameterMustBeOfTypeFacts() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithConditionMethodHavingOneArgumentNotOfTypeFacts()); + } + + @Test(expected = IllegalArgumentException.class) + public void conditionMethodMustReturnBooleanType() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithConditionMethodHavingNonBooleanReturnType()); + } + + /* + * Action method tests + */ + @Test(expected = IllegalArgumentException.class) + public void actionMethodMustBeDefined() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithoutActionMethod()); + } + + @Test(expected = IllegalArgumentException.class) + public void actionMethodMustBePublic() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithNotPublicActionMethod()); + } + + @Test(expected = IllegalArgumentException.class) + public void actionMethodMustHaveNoArguments() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithActionMethodHavingOneArgumentNotOfTypeFacts()); + } + + /* + * Priority method tests + */ + + @Test(expected = IllegalArgumentException.class) + public void priorityMethodMustBeUnique() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithMoreThanOnePriorityMethod()); + } + + @Test(expected = IllegalArgumentException.class) + public void priorityMethodMustBePublic() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithNotPublicPriorityMethod()); + } + + @Test(expected = IllegalArgumentException.class) + public void priorityMethodMustHaveNoArguments() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithPriorityMethodHavingArguments()); + } + + @Test(expected = IllegalArgumentException.class) + public void priorityMethodReturnTypeMustBeInteger() { + ruleDefinitionValidator.validateRuleDefinition(new AnnotatedRuleWithPriorityMethodHavingNonIntegerReturnType()); + } +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/RuleListenerTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/RuleListenerTest.java new file mode 100644 index 0000000..e50bc20 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/RuleListenerTest.java @@ -0,0 +1,158 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.api.RuleListener; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; + +import static org.mockito.Mockito.*; + +/** + * Test class of the execution of rule listeners. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public class RuleListenerTest extends AbstractTest { + + @Mock + private RuleListener ruleListener1, ruleListener2; + + @Before + public void setup() throws Exception { + super.setup(); + when(ruleListener1.beforeEvaluate(rule1, facts)).thenReturn(true); + when(ruleListener2.beforeEvaluate(rule1, facts)).thenReturn(true); + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withRuleListener(ruleListener1) + .withRuleListener(ruleListener2) + .build(); + } + + @Test + public void whenTheRuleExecutesSuccessfully_thenOnSuccessShouldBeExecuted() throws Exception { + when(rule1.evaluate(facts)).thenReturn(true); + rules.clear(); // FIXME + rules.register(rule1); + rulesEngine.fire(rules, facts); + + InOrder inOrder = inOrder(rule1, fact1, fact2, ruleListener1, ruleListener2); + inOrder.verify(ruleListener1).beforeExecute(rule1, facts); + inOrder.verify(ruleListener2).beforeExecute(rule1, facts); + inOrder.verify(ruleListener1).onSuccess(rule1, facts); + inOrder.verify(ruleListener2).onSuccess(rule1, facts); + + } + + @Test + public void whenTheRuleFails_thenOnFailureShouldBeExecuted() throws Exception { + + final Exception exception = new Exception("fatal error!"); + doThrow(exception).when(rule1).execute(facts); + when(rule1.evaluate(facts)).thenReturn(true); + + rules.clear(); // FIXME + rules.register(rule1); + + rulesEngine.fire(rules, facts); + + InOrder inOrder = inOrder(rule1, fact1, fact2, ruleListener1, ruleListener2); + inOrder.verify(ruleListener1).beforeExecute(rule1, facts); + inOrder.verify(ruleListener2).beforeExecute(rule1, facts); + inOrder.verify(ruleListener1).onFailure(rule1, exception, facts); + inOrder.verify(ruleListener2).onFailure(rule1, exception, facts); + + } + + @Test + public void whenListenerReturnsFalse_thenTheRuleShouldBeSkippedBeforeBeingEvaluated() throws Exception { + + // Given + when(ruleListener1.beforeEvaluate(rule1, facts)).thenReturn(false); + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withRuleListener(ruleListener1) + .build(); + + // When + rules.register(rule1); + rulesEngine.fire(rules, facts); + + // Then + verify(rule1, never()).evaluate(facts); + } + + @Test + public void whenListenerReturnsTrue_thenTheRuleShouldBeEvaluated() throws Exception { + + // Given + when(ruleListener1.beforeEvaluate(rule1, facts)).thenReturn(true); + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withRuleListener(ruleListener1) + .build(); + + // When + rules.register(rule1); + rulesEngine.fire(rules, facts); + + // Then + verify(rule1).evaluate(facts); + } + + @Test + public void whenTheRuleEvaluatesToTrue_thenTheListenerShouldBeInvoked() throws Exception { + // Given + when(rule1.evaluate(facts)).thenReturn(true); + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withRuleListener(ruleListener1) + .build(); + + // When + rules.clear(); + rules.register(rule1); + rulesEngine.fire(rules, facts); + + // Then + verify(ruleListener1).afterEvaluate(rule1, true); + } + + @Test + public void whenTheRuleEvaluatesToFalse_thenTheListenerShouldBeInvoked() throws Exception { + // Given + when(rule1.evaluate(facts)).thenReturn(false); + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withRuleListener(ruleListener1) + .build(); + + // When + rules.clear(); + rules.register(rule1); + rulesEngine.fire(rules, facts); + + // Then + verify(ruleListener1).afterEvaluate(rule1, false); + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/RulePriorityThresholdTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/RulePriorityThresholdTest.java new file mode 100644 index 0000000..7f8ecbc --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/RulePriorityThresholdTest.java @@ -0,0 +1,68 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.junit.Before; +import org.junit.Test; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Test class of rules priority comparison. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public class RulePriorityThresholdTest extends AbstractTest { + + @Before + public void setup() throws Exception { + super.setup(); + + when(rule1.getPriority()).thenReturn(1); + when(rule1.evaluate(facts)).thenReturn(true); + + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withRulePriorityThreshold(1) + .build(); + } + + @Test + public void rulesThatExceedPriorityThresholdMustNotBeExecuted() throws Exception { + + rules.register(rule1); + rules.register(rule2); + + rulesEngine.fire(rules, facts); + + //Rule 1 should be executed + verify(rule1).execute(facts); + + //Rule 2 should be skipped since its priority (2) exceeds priority threshold (1) + verify(rule2, never()).execute(facts); + + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/RuleProxyTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/RuleProxyTest.java new file mode 100644 index 0000000..7df5e6a --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/RuleProxyTest.java @@ -0,0 +1,43 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.annotation.AnnotatedRuleWithMetaRuleAnnotation; +import org.jeasy.rules.api.Rule; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +public class RuleProxyTest { + + @Test + public void proxyingHappensEvenWhenRuleIsAnnotatedWithMetaRuleAnnotation() { + AnnotatedRuleWithMetaRuleAnnotation rule1 = new AnnotatedRuleWithMetaRuleAnnotation(); + + Rule rule = RuleProxy.asRule(rule1); + + assertNotNull(rule.getDescription()); + assertNotNull(rule.getName()); + } +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/RulesEngineBuilderTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/RulesEngineBuilderTest.java new file mode 100644 index 0000000..6d5e5a2 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/RulesEngineBuilderTest.java @@ -0,0 +1,81 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.jeasy.rules.api.RuleListener; +import org.jeasy.rules.api.RulesEngine; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(MockitoJUnitRunner.class) +public class RulesEngineBuilderTest { + + @Mock + private RuleListener ruleListener; + + @Test + public void testCreationWithDefaultParameters() { + RulesEngine rulesEngine = RulesEngineBuilder.aNewRulesEngine().build(); + + assertThat(rulesEngine).isNotNull(); + RulesEngineParameters parameters = rulesEngine.getParameters(); + + assertThat(parameters.getName()).isEqualTo(RulesEngine.DEFAULT_NAME); + assertThat(parameters.getPriorityThreshold()).isEqualTo(RulesEngine.DEFAULT_RULE_PRIORITY_THRESHOLD); + + assertThat(parameters.isSkipOnFirstAppliedRule()).isFalse(); + assertThat(parameters.isSkipOnFirstFailedRule()).isFalse(); + assertThat(parameters.isSkipOnFirstNonTriggeredRule()).isFalse(); + } + + @Test + public void testCreationWithCustomParameters() { + String name = "myRulesEngine"; + int expectedThreshold = 10; + + RulesEngine rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .named(name) + .withRuleListener(ruleListener) + .withRulePriorityThreshold(expectedThreshold) + .withSilentMode(true) + .withSkipOnFirstNonTriggeredRule(true) + .withSkipOnFirstAppliedRule(true) + .withSkipOnFirstFailedRule(true) + .build(); + + assertThat(rulesEngine).isNotNull(); + RulesEngineParameters parameters = rulesEngine.getParameters(); + + assertThat(parameters.getName()).isEqualTo(name); + assertThat(parameters.getPriorityThreshold()).isEqualTo(expectedThreshold); + assertThat(parameters.isSilentMode()).isTrue(); + assertThat(parameters.isSkipOnFirstAppliedRule()).isTrue(); + assertThat(parameters.isSkipOnFirstFailedRule()).isTrue(); + assertThat(parameters.isSkipOnFirstNonTriggeredRule()).isTrue(); + } +} \ No newline at end of file diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstAppliedRuleTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstAppliedRuleTest.java new file mode 100644 index 0000000..f9a508f --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstAppliedRuleTest.java @@ -0,0 +1,80 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.junit.Before; +import org.junit.Test; + +import static org.jeasy.rules.core.RulesEngineBuilder.aNewRulesEngine; +import static org.mockito.Mockito.*; + +/** + * Test class of "skip on first applied rule" parameter of Easy Rules default engine. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public class SkipOnFirstAppliedRuleTest extends AbstractTest { + + @Before + public void setup() throws Exception { + super.setup(); + + setUpRule1(); + + rulesEngine = aNewRulesEngine() + .withSkipOnFirstAppliedRule(true) + .build(); + } + + @Test + public void testSkipOnFirstAppliedRule() throws Exception { + rulesEngine.fire(rules, facts); + + //Rule 1 should be executed + verify(rule1).execute(facts); + + //Rule 2 should be skipped since Rule 1 has been executed + verify(rule2, never()).execute(facts); + + } + + @Test + public void testSkipOnFirstAppliedRuleWithException() throws Exception { + rulesEngine.fire(rules, facts); + + //If an exception occurs when executing Rule 0, Rule 1 should still be applied + verify(rule1).execute(facts); + + //Rule 2 should be skipped since Rule 1 has been executed + verify(rule2, never()).execute(facts); + + } + + private void setUpRule1() throws Exception { + when(rule1.evaluate(facts)).thenReturn(true); + final Exception exception = new Exception("fatal error!"); + doThrow(exception).when(rule1).execute(facts); + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstFailedRuleTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstFailedRuleTest.java new file mode 100644 index 0000000..a43fde5 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstFailedRuleTest.java @@ -0,0 +1,68 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.junit.Before; +import org.junit.Test; + +import static org.mockito.Mockito.*; + +/** + * Test class of "skip on first failed rule" parameter of Easy Rules default engine. + * + * @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com) + */ +public class SkipOnFirstFailedRuleTest extends AbstractTest { + + @Before + public void setup() throws Exception { + super.setup(); + setUpRule1(); + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withSkipOnFirstFailedRule(true) + .build(); + } + + @Test + public void testSkipOnFirstFailedRule() throws Exception { + + rulesEngine.fire(rules, facts); + + //Rule 1 should be executed + verify(rule1).execute(facts); + + //Rule 2 should be skipped since Rule 1 has failed + verify(rule2, never()).execute(facts); + + } + + private void setUpRule1() throws Exception { + when(rule1.getName()).thenReturn("r1"); + when(rule1.getPriority()).thenReturn(1); + when(rule1.evaluate(facts)).thenReturn(true); + final Exception exception = new Exception("fatal error!"); + doThrow(exception).when(rule1).execute(facts); + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstNonTriggeredRuleTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstNonTriggeredRuleTest.java new file mode 100644 index 0000000..cae2c09 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/SkipOnFirstNonTriggeredRuleTest.java @@ -0,0 +1,66 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.junit.Before; +import org.junit.Test; + +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) + */ +public class SkipOnFirstNonTriggeredRuleTest extends AbstractTest { + + @Before + public void setup() throws Exception { + super.setup(); + setUpRule1(); + rulesEngine = RulesEngineBuilder.aNewRulesEngine() + .withSkipOnFirstNonTriggeredRule(true) + .build(); + } + + @Test + public void testSkipOnFirstNonTriggeredRule() throws Exception { + + rulesEngine.fire(rules, facts); + + //Rule1 is non triggered + verify(rule1, never()).execute(facts); + + //Rule 2 should be skipped since Rule 1 has not been executed + verify(rule2, never()).execute(facts); + + } + + private void setUpRule1() throws Exception { + when(rule1.getName()).thenReturn("r1"); + when(rule1.getPriority()).thenReturn(1); + when(rule1.evaluate(facts)).thenReturn(false); + } + +} diff --git a/easy-rules-core/src/test/java/org/jeasy/rules/core/UtilsTest.java b/easy-rules-core/src/test/java/org/jeasy/rules/core/UtilsTest.java new file mode 100644 index 0000000..0b326f4 --- /dev/null +++ b/easy-rules-core/src/test/java/org/jeasy/rules/core/UtilsTest.java @@ -0,0 +1,95 @@ +/** + * The MIT License + * + * Copyright (c) 2017, 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.jeasy.rules.core; + +import org.junit.Test; + +import java.lang.annotation.*; + +import static org.junit.Assert.*; + +public class UtilsTest { + + @Test + public void findAnnotationWithClassWhereAnnotationIsPresent() { + Annotation foo = Utils.findAnnotation(Foo.class, AnnotationIsPresent.class); + + assertCorrectAnnotationIsFound(Foo.class, foo); + } + + @Test + public void findAnnotationWithClassWhereAnnotationIsPresentViaMetaAnnotation() { + Annotation foo = Utils.findAnnotation(Foo.class, AnnotationIsPresentViaMetaAnnotation.class); + + assertCorrectAnnotationIsFound(Foo.class, foo); + } + + @Test + public void findAnnotationWithClassWhereAnnotationIsNotPresent() { + Annotation foo = Utils.findAnnotation(Foo.class, Object.class); + + assertNull(foo); + } + + @Test + public void isAnnotationPresentWithClassWhereAnnotationIsPresent() { + assertTrue(Utils.isAnnotationPresent(Foo.class, AnnotationIsPresent.class)); + } + + @Test + public void isAnnotationPresentWithClassWhereAnnotationIsPresentViaMetaAnnotation() { + assertTrue(Utils.isAnnotationPresent(Foo.class, AnnotationIsPresentViaMetaAnnotation.class)); + } + + @Test + public void isAnnotationPresentWithClassWhereAnnotationIsNotPresent() { + assertFalse(Utils.isAnnotationPresent(Foo.class, Object.class)); + } + + private static void assertCorrectAnnotationIsFound( + Class expectedAnnotationType, Annotation actualAnnotation) { + + assertNotNull(actualAnnotation); + assertEquals(expectedAnnotationType, actualAnnotation.annotationType()); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + private @interface Foo { + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @Foo + private @interface MetaFoo { + } + + @Foo + private static final class AnnotationIsPresent { + } + + @MetaFoo + private static final class AnnotationIsPresentViaMetaAnnotation { + } +} diff --git a/easyrules-gradle/README.md b/easy-rules-gradle/README.md similarity index 100% rename from easyrules-gradle/README.md rename to easy-rules-gradle/README.md diff --git a/easyrules-gradle/build.gradle b/easy-rules-gradle/build.gradle similarity index 100% rename from easyrules-gradle/build.gradle rename to easy-rules-gradle/build.gradle diff --git a/easyrules-gradle/gradle/wrapper/gradle-wrapper.jar b/easy-rules-gradle/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from easyrules-gradle/gradle/wrapper/gradle-wrapper.jar rename to easy-rules-gradle/gradle/wrapper/gradle-wrapper.jar diff --git a/easyrules-gradle/gradle/wrapper/gradle-wrapper.properties b/easy-rules-gradle/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from easyrules-gradle/gradle/wrapper/gradle-wrapper.properties rename to easy-rules-gradle/gradle/wrapper/gradle-wrapper.properties diff --git a/easyrules-gradle/gradlew b/easy-rules-gradle/gradlew similarity index 100% rename from easyrules-gradle/gradlew rename to easy-rules-gradle/gradlew diff --git a/easyrules-gradle/gradlew.bat b/easy-rules-gradle/gradlew.bat similarity index 96% rename from easyrules-gradle/gradlew.bat rename to easy-rules-gradle/gradlew.bat index e95643d..f955316 100644 --- a/easyrules-gradle/gradlew.bat +++ b/easy-rules-gradle/gradlew.bat @@ -1,84 +1,84 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/Launcher.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/Launcher.groovy similarity index 96% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/Launcher.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/Launcher.groovy index b670472..644d711 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/Launcher.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/Launcher.groovy @@ -4,7 +4,7 @@ import org.easyrules.samples.fire.rules.* import org.easyrules.samples.fire.beans.* -import static org.easyrules.core.RulesEngineBuilder.aNewRulesEngine as EasyRules +import static RulesEngineBuilder.aNewRulesEngine as EasyRules class Launcher { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/TheWorld.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/TheWorld.groovy similarity index 100% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/TheWorld.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/TheWorld.groovy diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Alarm.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Alarm.groovy similarity index 100% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Alarm.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Alarm.groovy diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Fire.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Fire.groovy similarity index 100% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Fire.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Fire.groovy diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Room.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Room.groovy similarity index 100% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Room.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Room.groovy diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Sprinkler.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Sprinkler.groovy similarity index 100% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Sprinkler.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/beans/Sprinkler.groovy diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/CancelAlarmRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/CancelAlarmRule.groovy similarity index 71% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/CancelAlarmRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/CancelAlarmRule.groovy index 744557f..29867e1 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/CancelAlarmRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/CancelAlarmRule.groovy @@ -1,9 +1,9 @@ package org.easyrules.samples.fire.rules -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Rule -import org.easyrules.annotation.Priority +import Action +import Condition +import Rule +import Priority @Rule(description='All the fires are out, cancel the alarm') class CancelAlarmRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/EverythingOKRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/EverythingOKRule.groovy similarity index 70% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/EverythingOKRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/EverythingOKRule.groovy index c435c8c..92982f6 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/EverythingOKRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/EverythingOKRule.groovy @@ -1,9 +1,9 @@ package org.easyrules.samples.fire.rules -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Rule -import org.easyrules.annotation.Priority +import Action +import Condition +import Rule +import Priority @Rule(description='No alarm, nothing to see here; This need to be last rule considered') class EverythingOKRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/RaiseAlarmRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/RaiseAlarmRule.groovy similarity index 72% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/RaiseAlarmRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/RaiseAlarmRule.groovy index 38c6cb5..dee8679 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/RaiseAlarmRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/RaiseAlarmRule.groovy @@ -2,10 +2,10 @@ package org.easyrules.samples.fire.rules import org.easyrules.samples.fire.beans.Alarm -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Rule -import org.easyrules.annotation.Priority +import Action +import Condition +import Rule +import Priority @Rule(description='A fire will raise an alarm') class RaiseAlarmRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/ThereIsAnAlarmRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/ThereIsAnAlarmRule.groovy similarity index 71% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/ThereIsAnAlarmRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/ThereIsAnAlarmRule.groovy index f5c0a07..a048bbd 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/ThereIsAnAlarmRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/ThereIsAnAlarmRule.groovy @@ -1,9 +1,9 @@ package org.easyrules.samples.fire.rules -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Rule -import org.easyrules.annotation.Priority +import Action +import Condition +import Rule +import Priority @Rule(description='The alarm is detected at the fire station') class ThereIsAnAlarmRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOffRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOffRule.groovy similarity index 77% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOffRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOffRule.groovy index f78a2f5..85ff209 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOffRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOffRule.groovy @@ -1,9 +1,9 @@ package org.easyrules.samples.fire.rules -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Rule -import org.easyrules.annotation.Priority +import Action +import Condition +import Rule +import Priority @Rule(description='The fires are out, turn off all of the sprinklers') class TurnSprinklerOffRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOnRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOnRule.groovy similarity index 81% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOnRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOnRule.groovy index 074c05f..e4e2469 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOnRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fire/rules/TurnSprinklerOnRule.groovy @@ -1,9 +1,9 @@ package org.easyrules.samples.fire.rules -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Rule -import org.easyrules.annotation.Priority +import Action +import Condition +import Rule +import Priority @Rule(description='A fire has been detected in a room, turn on the sprinkler in the room; Highest priority rule') class TurnSprinklerOnRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/BuzzRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/BuzzRule.groovy similarity index 58% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/BuzzRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/BuzzRule.groovy index e3de0d4..9a876f4 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/BuzzRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/BuzzRule.groovy @@ -1,9 +1,9 @@ package org.easyrules.samples.fizzbuzz -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Priority -import org.easyrules.annotation.Rule +import Action +import Condition +import Priority +import Rule @Rule class BuzzRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzz.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzz.groovy similarity index 100% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzz.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzz.groovy diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzRule.groovy similarity index 83% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzRule.groovy index 4cabf98..0ee935f 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzRule.groovy @@ -1,6 +1,6 @@ package org.easyrules.samples.fizzbuzz -import org.easyrules.core.CompositeRule +import CompositeRule class FizzBuzzRule extends CompositeRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzWithEasyRules.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzWithEasyRules.groovy similarity index 96% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzWithEasyRules.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzWithEasyRules.groovy index ad72831..8df8dc9 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzWithEasyRules.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzBuzzWithEasyRules.groovy @@ -1,6 +1,6 @@ package org.easyrules.samples.fizzbuzz -import org.easyrules.core.RulesEngineBuilder +import RulesEngineBuilder class FizzBuzzWithEasyRules { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzRule.groovy similarity index 58% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzRule.groovy index 795b83c..cc79880 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/FizzRule.groovy @@ -1,9 +1,9 @@ package org.easyrules.samples.fizzbuzz -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Priority -import org.easyrules.annotation.Rule +import Action +import Condition +import Priority +import Rule @Rule class FizzRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/NonFizzBuzzRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/NonFizzBuzzRule.groovy similarity index 60% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/NonFizzBuzzRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/NonFizzBuzzRule.groovy index 51f5873..3c28be5 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/NonFizzBuzzRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/fizzbuzz/NonFizzBuzzRule.groovy @@ -1,9 +1,9 @@ package org.easyrules.samples.fizzbuzz -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Priority -import org.easyrules.annotation.Rule +import Action +import Condition +import Priority +import Rule @Rule class NonFizzBuzzRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/helloworld/HelloWorldRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/helloworld/HelloWorldRule.groovy similarity index 80% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/helloworld/HelloWorldRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/helloworld/HelloWorldRule.groovy index d545001..b863884 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/helloworld/HelloWorldRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/helloworld/HelloWorldRule.groovy @@ -1,8 +1,8 @@ package org.easyrules.samples.helloworld -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Rule +import Action +import Condition +import Rule @Rule(name = "Hello World rule", description = "Say Hello to duke's friends only") class HelloWorldRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/helloworld/Launcher.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/helloworld/Launcher.groovy similarity index 91% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/helloworld/Launcher.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/helloworld/Launcher.groovy index 8a83089..f6224f2 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/helloworld/Launcher.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/helloworld/Launcher.groovy @@ -1,6 +1,6 @@ package org.easyrules.samples.helloworld -import static org.easyrules.core.RulesEngineBuilder.aNewRulesEngine +import static RulesEngineBuilder.aNewRulesEngine import java.util.Scanner class Launcher { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/scheduling/Launcher.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/scheduling/Launcher.groovy similarity index 95% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/scheduling/Launcher.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/scheduling/Launcher.groovy index 2c6873c..6da7a50 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/scheduling/Launcher.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/scheduling/Launcher.groovy @@ -1,6 +1,6 @@ package org.easyrules.samples.scheduling -import org.easyrules.core.RulesEngineBuilder +import RulesEngineBuilder import org.easyrules.quartz.RulesEngineScheduler import java.util.Date diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/scheduling/TimeRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/scheduling/TimeRule.groovy similarity index 76% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/scheduling/TimeRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/scheduling/TimeRule.groovy index cb9932a..a05f8d7 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/scheduling/TimeRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/scheduling/TimeRule.groovy @@ -1,8 +1,8 @@ package org.easyrules.samples.scheduling -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Rule +import Action +import Condition +import Rule import java.util.Date diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/AgeRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/AgeRule.groovy similarity index 93% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/AgeRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/AgeRule.groovy index 03b3dff..7b0bed6 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/AgeRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/AgeRule.groovy @@ -1,6 +1,6 @@ package org.easyrules.samples.shop -import org.easyrules.core.BasicRule +import BasicRule public class AgeRule extends BasicRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/Launcher.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/Launcher.groovy similarity index 88% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/Launcher.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/Launcher.groovy index ae25dbf..cd54c69 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/Launcher.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/Launcher.groovy @@ -1,8 +1,8 @@ package org.easyrules.samples.shop -import static org.easyrules.core.RulesEngineBuilder.aNewRulesEngine +import static RulesEngineBuilder.aNewRulesEngine -import org.easyrules.api.RulesEngine +import RulesEngine class Launcher { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/OkToSellRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/OkToSellRule.groovy similarity index 77% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/OkToSellRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/OkToSellRule.groovy index 569bc9c..62de47c 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/OkToSellRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/OkToSellRule.groovy @@ -1,8 +1,8 @@ package org.easyrules.samples.shop -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.core.BasicRule +import Action +import Condition +import BasicRule class OkToSellRule extends BasicRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/Person.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/Person.groovy similarity index 100% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/Person.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/Person.groovy diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/UnderAgeRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/UnderAgeRule.groovy similarity index 78% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/UnderAgeRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/UnderAgeRule.groovy index 1952b25..3fbe001 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/shop/UnderAgeRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/shop/UnderAgeRule.groovy @@ -1,8 +1,8 @@ package org.easyrules.samples.shop -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.core.BasicRule +import Action +import Condition +import BasicRule class UnderAgeRule extends BasicRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/simple/Launcher.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/simple/Launcher.groovy similarity index 88% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/simple/Launcher.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/simple/Launcher.groovy index 2c45609..3687194 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/simple/Launcher.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/simple/Launcher.groovy @@ -1,6 +1,6 @@ package org.easyrules.samples.simple -import static org.easyrules.core.RulesEngineBuilder.aNewRulesEngine +import static RulesEngineBuilder.aNewRulesEngine class Launcher { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/simple/SimpleRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/simple/SimpleRule.groovy similarity index 55% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/simple/SimpleRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/simple/SimpleRule.groovy index f058012..a45db70 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/simple/SimpleRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/simple/SimpleRule.groovy @@ -1,9 +1,9 @@ package org.easyrules.samples.simple -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Priority -import org.easyrules.annotation.Rule +import Action +import Condition +import Priority +import Rule @Rule public class SimpleRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/spring/DummyRule.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/spring/DummyRule.groovy similarity index 63% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/spring/DummyRule.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/spring/DummyRule.groovy index dcba4cd..c67b327 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/spring/DummyRule.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/spring/DummyRule.groovy @@ -1,8 +1,8 @@ package org.easyrules.samples.spring -import org.easyrules.annotation.Action -import org.easyrules.annotation.Condition -import org.easyrules.annotation.Rule +import Action +import Condition +import Rule @Rule(name = "dummy rule") class DummyRule { diff --git a/easyrules-gradle/src/main/groovy/org/easyrules/samples/spring/Launcher.groovy b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/spring/Launcher.groovy similarity index 94% rename from easyrules-gradle/src/main/groovy/org/easyrules/samples/spring/Launcher.groovy rename to easy-rules-gradle/src/main/groovy/org/easyrules/samples/spring/Launcher.groovy index 5a12cae..ecafb0a 100644 --- a/easyrules-gradle/src/main/groovy/org/easyrules/samples/spring/Launcher.groovy +++ b/easy-rules-gradle/src/main/groovy/org/easyrules/samples/spring/Launcher.groovy @@ -1,6 +1,6 @@ package org.easyrules.samples.spring -import org.easyrules.api.RulesEngine +import RulesEngine import org.springframework.context.support.ClassPathXmlApplicationContext class Launcher { diff --git a/easyrules-gradle/src/main/resources/logging.properties b/easy-rules-gradle/src/main/resources/logging.properties similarity index 100% rename from easyrules-gradle/src/main/resources/logging.properties rename to easy-rules-gradle/src/main/resources/logging.properties diff --git a/easyrules-gradle/src/main/resources/org/easyrules/samples/spring/application-context.xml b/easy-rules-gradle/src/main/resources/org/easyrules/samples/spring/application-context.xml similarity index 100% rename from easyrules-gradle/src/main/resources/org/easyrules/samples/spring/application-context.xml rename to easy-rules-gradle/src/main/resources/org/easyrules/samples/spring/application-context.xml diff --git a/pom.xml b/pom.xml index f94a74f..720c00d 100644 --- a/pom.xml +++ b/pom.xml @@ -8,20 +8,20 @@ 7 - org.easyrules - easyrules + org.jeasy + easy-rules 3.0.0-SNAPSHOT - easyrules-archetype - easyrules-core + easy-rules-archetype + easy-rules-core pom Easy Rules - Easy Rules is a simple, stupid Java rules engine - http://www.easyrules.org + Easy Rules is a simple, stupid rules engine for Java + http://www.github.com/j-easy/easy-rules UTF-8 @@ -39,20 +39,20 @@ - git@github.com:EasyRules/easyrules.git - scm:git:git@github.com:EasyRules/easyrules.git - scm:git:git@github.com:EasyRules/easyrules.git + git@github.com:j-easy/easy-rules.git + scm:git:git@github.com:j-easy/easy-rules.git + scm:git:git@github.com:j-easy/easy-rules.git HEAD GitHub - https://github.com/EasyRules/easyrules/issues + https://github.com/j-easy/easy-rules/issues Travis CI - https://travis-ci.org/EasyRules/easyrules + https://travis-ci.org/j-easy/easy-rules