update documentation for version 2.2

pull/55/head
Mahmoud Ben Hassine 9 years ago
parent 63cbddf7fe
commit 3ad299a699

@ -19,6 +19,9 @@
<li class="{% if page.title == "Defining rules" %}current{% endif %}">
<a href="{{ site.url }}/user-guide/defining-rules.html">Defining rules</a>
</li>
<li class="{% if page.title == "Rule listener" %}current{% endif %}">
<a href="{{ site.url }}/user-guide/rule-listener.html">Rule listener</a>
</li>
<li class="{% if page.title == "Rules engine" %}current{% endif %}">
<a href="{{ site.url }}/user-guide/rules-engine.html">Rules engine</a>
</li>
@ -26,28 +29,25 @@
<a href="{{ site.url }}/user-guide/managing-rules.html">Managing rules</a>
</li>
<li class="{% if page.title == "Scheduling rules engine" %}current{% endif %}">
<a href="{{ site.url }}/user-guide/scheduling-rules-engine.html">Scheduling rules engine</a>
<a href="{{ site.url }}/user-guide/scheduling-rules-engine.html">Scheduling a rules engine</a>
</li>
<li class="{% if page.title == "Embedding rules engine" %}current{% endif %}">
<a href="{{ site.url }}/user-guide/embedding-rules-engine.html">Embedding rules engine</a>
<a href="{{ site.url }}/user-guide/embedding-rules-engine.html">Embedding a rules engine</a>
</li>
</ul>
<h4>Tutorials</h4>
<ul>
<li class="{% if page.title == "Hello World" %}current{% endif %}">
<a href="{{ site.url }}/tutorials/hello-world.html">Hello World</a>
</li>
<li class="{% if page.title == "Rule Priority" %}current{% endif %}">
<a href="{{ site.url }}/tutorials/rule-priority.html">Rule Priority</a>
<li class="{% if page.title == "Hello world tutorial" %}current{% endif %}">
<a href="{{ site.url }}/tutorials/hello-world-tutorial.html">Hello world tutorial</a>
</li>
<li class="{% if page.title == "Dynamic configuration" %}current{% endif %}">
<a href="{{ site.url }}/tutorials/dynamic-configuration.html">Dynamic configuration</a>
<li class="{% if page.title == "Shop tutorial" %}current{% endif %}">
<a href="{{ site.url }}/tutorials/shop-tutorial.html">Shop tutorial</a>
</li>
<li class="{% if page.title == "Engine scheduler" %}current{% endif %}">
<a href="{{ site.url }}/tutorials/scheduling-engine.html">Engine scheduler</a>
<li class="{% if page.title == "Scheduler tutorial" %}current{% endif %}">
<a href="{{ site.url }}/tutorials/scheduler-tutorial.html">Scheduler tutorial</a>
</li>
<li class="{% if page.title == "Using Easy Rules with Spring" %}current{% endif %}">
<li class="{% if page.title == "Spring tutorial" %}current{% endif %}">
<a href="{{ site.url }}/tutorials/spring-tutorial.html">Spring tutorial</a>
</li>
</ul>

@ -7,7 +7,7 @@ next_section: user-guide/introduction
doc: true
---
Easy Rules is a Java library. It requires a Java 1.5+ runtime.
Easy Rules is a Java library. It requires a Java 1.7+ runtime.
## Building from source
@ -27,7 +27,7 @@ Easy Rules core jar **_easyrules-core-{{site.version}}.jar_** will be generated
Easy Rules is a single jar file with no dependencies. You have to add the jar **_easyrules-core-{{site.version}}.jar_** to your application's classpath.
If you use maven, you should add the following dependency to your **_pom.xml_** :
If you use maven, add the following dependency to your **_pom.xml_** :
```xml
<dependency>
@ -57,5 +57,3 @@ $>mvn compile exec:java -Dexec.mainClass=${your.base.package}.Launcher
```
where `${your.base.package}` is the value of the base package you were asked for when creating the project.
Finally, you can import this maven project into your favorite IDE and tweak the application to your needs.

@ -57,7 +57,7 @@ body > header small {
}
body > header h1 span {
font-size: 1.5em;
font-size: 1.3em;
}
body > header .shadow {

@ -83,14 +83,14 @@ public class AgeRule {
public void markAsAdult(){
person.setAdult(true);
System.out.printf(
"Person %s has been marked as adult.\n",
"Person %s has been marked as adult",
person.getName());
}
}
```
The `Person` type is a simple Pojo having a `name` and `age` fields. Let's register multiple instances of the `AgeRule`:
The `Person` type is a simple POJO having a `name` and `age` fields. Let's register multiple instances of the `AgeRule`:
```java
Person tom = new Person("Tom", 20);
@ -160,6 +160,18 @@ Yes. Thanks to the community, Easy Rules has been made Android compatible since
Sure. Easy Rules is very lightweight and can be used both in a standalone application or embedded in an application server,
a servlet container or a dependency injection container.
## <a name="6"></a>[6. I have another question, how do I do?](#6)
## <a name="6"></a>[6. How to deal with tread safety?](#6)
Feel free to ask your question in the [Gitter](https://gitter.im/benas/easy-rules) channel of the project: [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/benas/easy-rules?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
If you run Easy Rules in a multi-threaded environment, you should take into account the following considerations:
* Easy Rules engine holds a set of rules, it is **not** thread safe.
* By design, rules in Easy Rules encapsulate the business object model they operate on, so they are **not** thread safe neither.
Do not try to make everything synchronized or locked down! Easy Rules engine is very a lightweight object
and you can create an instance per thread, this is by far the easiest way to avoid thread safety problems.
And if, at this exact point of time reading this line, you are already thinking about performance,
don't forget that <a href="http://c2.com/cgi/wiki?PrematureOptimization" target="_blank"><em>"Premature optimization is the root of all evil" - Donald Knuth</em></a>.
## <a name="7"></a>[7. I have another question, how do I do?](#7)
Feel free to ask your question in the [Gitter](https://gitter.im/benas/easy-rules) channel of the project: [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/benas/easy-rules?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

@ -8,9 +8,35 @@ doc: true
<article>
<h2>
<a href="/get-involoved/release-notes.html">{{ page.title }}</a>
<a href="/get-involved/release-notes.html">{{ page.title }}</a>
</h2>
<div class="release">
<span class="post-category">
<span class="label">Version 2.2.0</span>
</span>
<div class="post-meta">
<span class="post-date">2015-12-07</span>
</div>
<div class="post-content">
<p>This release adds the following features:</p>
<ul>
<li>New method <code>getRules()</code> in the <code>RulesEngine</code> API to get registered rules in a rules engine
(<a href="https://github.com/benas/easy-rules/issues/22" target="_blank">Issue #22</a>).</li>
<li>New method <code>getParameters()</code> in the <code>RulesEngine</code> API to get engine parameters
encapsulated in the <code>RulesEngineParameters</code> class
(<a href="https://github.com/benas/easy-rules/issues/28" target="_blank">Issue #28</a>).</li>
<li>New <code>@SpringRule</code> that turns a POJO into a Spring prototype-scoped rule bean
(<a href="https://github.com/benas/easy-rules/issues/29" target="_blank">Issue #29</a>).</li>
<li>Support for meta-annotations: You can now define your own annotation which itself is annotated with <code>@Rule</code>
(<a href="https://github.com/benas/easy-rules/pull/26" target="_blank">PR #26</a>).</li>
<li>The default rule name is now equal to the class name (<a href="https://github.com/benas/easy-rules/issues/24" target="_blank">Issue #24</a>).</li>
<li>The default rule description is now equal to <code>when[ConditionMethod]then[ActionMethods]</code> (<a href="https://github.com/benas/easy-rules/issues/24" target="_blank">Issue #24</a>).</li>
</ul>
<p>This version also added many improvements, bug fixes and documentation updates.</p>
</div>
</div>
<div class="release">
<span class="post-category">
<span class="label">Version 2.1.0</span>
@ -140,4 +166,4 @@ doc: true
</ul>
</div>
</div>
</article>
</article>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

@ -17,21 +17,21 @@ overview: true
<div class="unit one-third">
<h2>Lightweight</h2>
<p>
A tiny jar with no dependencies and a lot of features!
A zero dependencies jar with a lot of features! Use it in a standalone or embedded mode.
</p>
<a href="{{ site.url }}/about/getting-started.html" class="">Get started &rarr;</a>
</div>
<div class="unit one-third">
<h2>POJO based</h2>
<p>
Turn your POJOs into business rules with a couple of annotations.
Turn your POJOs into business rules with a couple of intuitive annotations.
</p>
<a href="{{ site.url }}/about/overview.html" class="">Read documentation &rarr;</a>
</div>
<div class="unit one-third">
<h2>Simple yet powerful</h2>
<p>
Easy rules provides a simple API to get you up and running quickly.
Easy rules provides a simple API that is easy to learn. You can get it up and running in minutes!
</p>
<a href="{{ site.url }}/tutorials/hello-world.html" class="">2 minutes tutorial &rarr;</a>
</div>
@ -84,8 +84,9 @@ overview: true
<div class="unit whole">
<div class="pane-content">
<h2>Latest news</h2>
<p><strong>06/12/2015:</strong> Version 2.2 is here with meta-annotation support! Check what's new <a href="./get-involved/release-notes.html">here</a>.</p>
<p><strong>28/06/2015:</strong> Version 2.1 is out with <a href="http://www.spring.io" target="_blank">Spring</a> and <a href="http://www.quartz-scheduler.org" target="_blank">Quartz</a> support. Check what's new <a href="./get-involved/release-notes.html">here</a>.</p>
<p><strong>21/05/2015:</strong> Version 2.0 is released! checkout what's new <a href="./get-involved/release-notes.html">here</a>.</p>
<p><strong>21/05/2015:</strong> Version 2.0 is finally released! checkout what's new <a href="./get-involved/release-notes.html">here</a>.</p>
</div>
<div class="pane-content">

@ -1,224 +0,0 @@
---
layout: docs
title: Dynamic configuration
header: Online shop tutorial
prev_section: tutorials/rule-priority
next_section: tutorials/scheduling-engine
doc: true
---
In this tutorial, we have an online shop application and we would like to implement the following requirements:
1. Whenever a new customer places an order with an amount greater than a defined threshold, send an alert about this suspect order to the monitoring team.
2. Moreover, the order amount threshold should be configurable via JMX so we can change it at runtime.
In the first part of this tutorial, we will see how to use Easy Rules to implement the business rule described in requirement #1.
In the second part, we will add JMX capability to the business rule developed in part 1 to be able to change the order amount threshold at runtime (requirement #2).
## Part 1 : Implementing the business rule
In this application, orders and customers are represented by the _Order_ and _Customer_ classes:
```java
class Order {
private long orderId;
private float amount;
//getters and setters
}
```
<br/>
```java
class Customer {
private long customerId;
private boolean isNew;
//getters and setters
}
```
First, let's implement the rule's logic by extending the `BasicRule` class:
```java
public class SuspectOrderRule extends BasicRule {
private float suspectOrderAmountThreshold = 1000;
private Order order;
private Customer customer;
SuspectOrderRule(String name, String description) {
super(name, description);
}
@Override
public boolean evaluate() {
return order.getAmount() > suspectOrderAmountThreshold
&& customer.isNew();
}
@Override
public void execute() throws Exception {
System.out.printf("Alert : A new customer [id=%s] has placed an order [id=%s] with amount %f > %f\n",
customer.getCustomerId(), order.getOrderId(), order.getAmount(), suspectOrderAmountThreshold);
}
// getters and setters for customer and order fields
}
```
This rule operates on an order and a customer instances which represent the business data to operate on.
The `evaluate` method evaluates to true when the customer is new and the order amount is greater than the defined threshold.
The `execute` method simply writes to the console the specified alert (this could be sending an email or another action in a real use case).
Then, let's create a `JmxRulesEngine` and register the `SuspectOrderRule` rule:
```java
public class Launcher {
public static void main(String[] args) {
Order order = new Order(6654, 1200);
Customer customer = new Customer(2356, true);
/**
* Create a business rule instance
*/
SuspectOrderRule suspectOrderRule = new SuspectOrderRule(
"Suspect Order",
"Send alert if a new customer places an order with amount greater than a threshold");
/**
* Set data to operate on
*/
suspectOrderRule.setOrder(order);
suspectOrderRule.setCustomer(customer);
/**
* Create a rules engine and register the business rule
*/
JmxRulesEngine rulesEngine = aNewJmxRulesEngine().build();
rulesEngine.registerJmxRule(suspectOrderRule);
/**
* Fire rules
*/
rulesEngine.fireRules();
}
}
```
To run this tutorial, you can follow these instructions from the root directory of Easy Rules :
{% highlight bash %}
$ mvn install
$ cd easyrules-samples
$ mvn exec:java -P runOnlineShopTutorial
{% endhighlight %}
When you run this tutorial, the rule named _Suspect Order_ that we registered will be applied since the order amount (1200) is greater than the threshold (1000) and the customer 2356 is a new customer.
## Part 2 : Changing the order amount threshold at runtime
In this tutorial, we need to expose the order amount threshold as a JMX attribute. So first, let's define an interface that allows us to change order amount threshold via JMX:
```java
@javax.management.MXBean
public interface SuspectOrderJmxRule extends JmxRule {
/**
* Get the current suspect order amount threshold
* @return current suspect order amount threshold
*/
float getSuspectOrderAmountThreshold();
/**
* Set the suspect order amount threshold
* @param suspectOrderAmountThreshold the new suspect order amount threshold
*/
void setSuspectOrderAmountThreshold(float suspectOrderAmountThreshold);
}
```
Then, we should make our `SuspectOrderRule` implement the `SuspectOrderJmxRule` interface to expose the order amount threshold as a JMX attribute.
So here is the new `SuspectOrderRule` class:
```java
public class SuspectOrderRule extends BasicRule implements SuspectOrderJmxRule {
// same implementation of the rule
public float getSuspectOrderAmountThreshold() {
return suspectOrderAmountThreshold;
}
public void setSuspectOrderAmountThreshold(float suspectOrderAmountThreshold) {
this.suspectOrderAmountThreshold = suspectOrderAmountThreshold;
}
}
```
Finally, let's suspend the program to change the order amount threshold value at runtime via any compliant JMX client and see the engine behavior after this change:
```java
public class Launcher {
public static void main(String[] args) throws InterruptedException {
Order order = new Order(6654, 1200);
Customer customer = new Customer(2356, true);
/**
* Create a business rule instance
*/
SuspectOrderRule suspectOrderRule = new SuspectOrderRule(
"Suspect Order",
"Send alert if a new customer places an order with amount greater than a threshold");
/**
* Set data to operate on
*/
suspectOrderRule.setOrder(order);
suspectOrderRule.setCustomer(customer);
/**
* Create a Jmx rules engine and register the business rule
*/
JmxRulesEngine rulesEngine = aNewJmxRulesEngine().build();
rulesEngine.registerJmxRule(suspectOrderRule);
/**
* Fire rules
*/
rulesEngine.fireRules();
// Update suspect order amount threshold via a JMX client.
Scanner scanner = new Scanner(System.in);
System.out.println("Change suspect order amount threshold to a value > 1200 via a JMX client and then press enter");
scanner.nextLine();
System.out.println("**************************************************************");
System.out.println("Re fire rules after updating suspect order amount threshold...");
System.out.println("**************************************************************");
rulesEngine.fireRules();
}
}
```
In the next screenshot, we use VisualVM to change the threshold value:
<img style="width: 100%" src="{{site.url}}/img/jmx-suspectOrderRule.png">
If you change the threshold value to 1400 for example, you will see that the rule _Suspect Order_ will not be applied the second time since the order amount (1200) is no longer greater than the new threshold (1400).
That's all! In this tutorial, we have seen how to create a real business rule with Easy Rules and how to reconfigure it at runtime.

@ -1,14 +1,14 @@
---
layout: docs
title: Hello World
title: Hello world tutorial
header: Hello World tutorial
prev_section: user-guide/managing-rules
next_section: tutorials/rule-priority
prev_section: user-guide/embedding-rules-engine
next_section: tutorials/shop-tutorial
doc: true
---
This tutorial shows how to use Easy Rules in a very simple application.
The program should ask the user if he is a friend of duke and says 'Hello duke's friend!' only if he replies 'yes'.
The goal is to ask the user if he is a friend of duke and says 'Hello duke's friend!' only if he replies 'yes'.
Based on this requirement, the rule is pretty straightforward :

@ -1,160 +0,0 @@
---
layout: docs
title: Rule Priority
header: Rule Priority tutorial
prev_section: tutorials/hello-world
next_section: tutorials/dynamic-configuration
doc: true
---
This tutorial shows how to define priority in which rules must be fired.
In Easy Rules, every rule has a priority. Rules are fired by default according to their priorities (this can be changed as described in the [user guide]({{site.url}}/user-guide/defining-rules.html#rules-priorities)).
In this tutorial, we have an application that sells alcohol. The application must flag the customer as adult if his age is greater than 18,
and must deny children from buying alcohol. Customers are represented by the following `Person` class:
```java
public class Person {
private String name;
private int age;
private boolean adult;
//getters and setters omitted
}
```
Based on these requirements, we can define the following rules:
* Rule 1: should operate an a `Person` instance, check that the person age is greater than 18 and set the adult flag.
* Rule 2: should operate an a `Person` instance, check that the person is adult and deny children (ie, non adult) from buying alcohol.
Rule 1 should be fired **_before_** rule 2. We will set rule 1 priority to 1 and rule 2 priority to 2 so that Easy Rules engine fire them in this order.
First, let's create a class for rule 1:
```java
@Rule(name = "AgeRule",
description = "Check if person's age is > 18
and marks the person as adult")
public class AgeRule {
private Person person;
private int adultAge = 18;
public AgeRule(Person person) {
this.person = person;
}
@Condition
public boolean isAdult() {
return person.getAge() > adultAge;
}
@Action
public void markAsAdult(){
person.setAdult(true);
System.out.printf(
"Person %s has been marked as adult.\n",
person.getName());
}
@Priority
public int getPriority() {
return 1;
}
}
```
As required, this rule class operates on a person that is passed at construction time.
The `isAdult` method annotated with `@Condition` tells Easy Rules engine to call this method to check if the rule should be fired, in this case, if the person's age is greater than 18.
The `markAsAdult` method annotated with `@Action` will mark the person as adult by setting the `adult` flag.
Finally, the `getPriority` method annotated with `@Priority` tells Easy Rules engine to fire this rule in first order.
Now, let's create a class for rule 2:
```java
@Rule(name = "alcoholRule",
description = "Children are not allowed to buy alcohol.")
public class AlcoholRule {
private Person person;
public AlcoholRule(Person person) {
this.person = person;
}
@Condition
public boolean isChildren() {
return !person.isAdult();
}
@Action
public void denyAlcohol(){
System.out.printf(
"Sorry %s, you are not allowed to buy alcohol.\n",
person.getName());
}
@Priority
public int getPriority() {
return 2;
}
}
```
As for rule 1, the class operates on a person instance and provides methods to define rule condition, action and priority.
To launch the tutorial, we will use the following class:
```java
public class Launcher {
public static void main(String[] args) {
//create a person instance
Person tom = new Person("Tom", 16);
System.out.println(
"Tom: Hi! can I have some Vodka please?");
//create a rules engine
RulesEngine rulesEngine = aNewRulesEngine().build();
//register rules
rulesEngine.registerRule(new AgeRule(tom));
rulesEngine.registerRule(new AlcoholRule(tom));
//fire rules
rulesEngine.fireRules();
}
}
```
To run the tutorial, you can follow these instructions from the root directory of Easy Rules :
{% highlight bash %}
$ mvn install
$ cd easyrules-samples
$ mvn exec:java -P runRulePriorityTutorial
{% endhighlight %}
If you run this tutorial, you would get the following output:
```
Tom: Hi! can I have some Vodka please?
INFO: Rule alcoholRule triggered.
Sorry Tom, you are not allowed to buy alcohol.
INFO: Rule alcoholRule performed successfully.
```
As expected, since Tom's age is under 18, he has not been allowed to buy alcohol.

@ -1,13 +1,13 @@
---
layout: docs
title: Engine scheduler
header: Engine scheduler
prev_section: tutorials/dynamic-configuration
title: Scheduler tutorial
header: Scheduler tutorial
prev_section: tutorials/shop-tutorial
next_section: tutorials/spring-tutorial
doc: true
---
This tutorial shows how to schedule a rules engine using the `RulesEngineScheduler`.
This tutorial shows how to schedule a rules engine using the `RulesEngineScheduler` API.
We would like to print the current time only if the seconds value is even. So let's get started.
@ -15,7 +15,8 @@ First, we will create a rule that checks the current time and print it to the co
```java
@Rule(name = "time rule",
description = "Print the current time only if seconds are even")
description = "Print the current time
only if seconds are even")
public class TimeRule {
private Date now;
@ -45,7 +46,8 @@ public class Launcher {
public static void main(String[] args) throws Exception {
RulesEngine rulesEngine = RulesEngineBuilder.aNewRulesEngine()
RulesEngine rulesEngine = RulesEngineBuilder
.aNewRulesEngine()
.named("time rules engine")
.withSilentMode(true)
.build();
@ -53,18 +55,21 @@ public class Launcher {
TimeRule timeRule = new TimeRule();
rulesEngine.registerRule(timeRule);
RulesEngineScheduler scheduler = RulesEngineScheduler.getInstance();
scheduler.scheduleAtWithInterval(rulesEngine, NOW, EVERY_SECOND);
RulesEngineScheduler scheduler =
RulesEngineScheduler.getInstance();
scheduler.scheduleAtWithInterval(rulesEngine,
NOW,
EVERY_SECOND);
scheduler.start();
System.out.println("Hit enter to stop the application");
System.out.println("Hit 'enter' to stop the application");
System.in.read();
scheduler.stop();
}
}
```
That's it! The `TimeRule` will be triggered every second and will print the current time if seconds value is even.
That's it! The `TimeRule` will be triggered every second and will print the current time only if seconds value is even.
To run this tutorial, you can follow these instructions from the root directory of Easy Rules :

@ -0,0 +1,261 @@
---
layout: docs
title: Shop tutorial
header: Shop tutorial
prev_section: tutorials/hello-world-tutorial
next_section: tutorials/scheduler-tutorial
doc: true
---
In this tutorial, we have a shop application and we would like to implement the following requirement: deny children from buying alcohol.
The minimal legal age to be considered as adult is 18. This tutorial is split in two parts:
1. Part 1: Implement the business rule of denying children from buying alcohol
2. Part 2: Make the legal age configurable via JMX so we can change it at runtime
## Part 1 : Implement the business rule
Our shop customers are represented by the _Person_ class:
```java
public class Person {
private String name;
private int age;
private boolean adult;
//getters and setters omitted
}
```
We will define the following rules:
* Rule 1: should operate an a `Person` instance, check that the person age is greater than 18 and set the adult flag.
* Rule 2: should operate an a `Person` instance, check that the person is adult and deny children (ie, non adult) from buying alcohol.
Rule 1 should be fired **_before_** rule 2. We will set rule 1 priority to 1 and rule 2 priority to 2 so that Easy Rules engine fire them in this order.
First, let's create a class for rule 1:
```java
public class AgeRule extends BasicRule {
private static final int ADULT_AGE = 18;
private Person person;
public AgeRule(Person person) {
super("AgeRule",
"Check if person's age is > 18 and
marks the person as adult", 1);
this.person = person;
}
@Override
public boolean evaluate() {
return person.getAge() > ADULT_AGE;
}
@Override
public void execute() {
person.setAdult(true);
System.out.printf("Person %s has been marked as adult",
person.getName());
}
}
```
As required, this rule class operates on a person that is passed at construction time.
The `evaluate` method checks if the person's age is greater than 18.
The `execute` will mark the person as adult by setting the `adult` flag.
Finally, the third constructor argument which represents the rule priority is set to 1 to tells Easy Rules engine to fire this rule in first order.
Now, let's create a class for rule 2:
```java
public class AlcoholRule extends BasicRule {
private Person person;
public AlcoholRule(Person person) {
super("AlcoholRule",
"Children are not allowed to buy alcohol",
2);
this.person = person;
}
@Condition
public boolean evaluate() {
return !person.isAdult();
}
@Action
public void execute(){
System.out.printf("Shop: Sorry %s,
you are not allowed to buy alcohol",
person.getName());
}
}
```
As for rule 1, the class operates on a person instance and prints the denial message for children.
To launch the tutorial, we will use the following class:
```java
public class Launcher {
public static void main(String[] args) {
//create a person instance
Person tom = new Person("Tom", 14);
System.out.println("Tom:
Hi! can I have some Vodka please?");
//create a rules engine
RulesEngine rulesEngine = aNewRulesEngine()
.named("shop rules engine")
.build();
//register rules
rulesEngine.registerRule(new AgeRule(tom));
rulesEngine.registerRule(new AlcoholRule(tom));
//fire rules
rulesEngine.fireRules();
}
}
```
To run the first part of the tutorial, you can follow these instructions from the root directory of Easy Rules :
{% highlight bash %}
$ mvn install
$ cd easyrules-samples
$ mvn exec:java -P runShopTutorialPart1
{% endhighlight %}
You should get the following output:
```
Tom: Hi! can I have some Vodka please?
INFO: Rule alcoholRule triggered.
Shop: Sorry Tom, you are not allowed to buy alcohol
INFO: Rule alcoholRule performed successfully.
```
As expected, since Tom's age is under 18, he has not been allowed to buy alcohol.
## Part 2 : Changing the legal adult age at runtime
In this second part, we will expose the legal adult age as a JMX attribute.
So first, let's define an interface that allows us to change this age via JMX:
```java
@javax.management.MXBean
public interface AgeJmxRule extends JmxRule {
int getAdultAge();
void setAdultAge(int adultAge);
}
```
Then, we should make our `AgeRule` implement the `AgeJmxRule` interface to expose the the legal adult age as a JMX attribute.
So here is the new `AgeRule` class:
```java
public class AgeRule extends BasicRule implements AgeJmxRule {
private int adultAge = 18;
private Person person;
public AgeRule(Person person) {
super("AgeRule",
"Check if person's age is > 18
and marks the person as adult", 1);
this.person = person;
}
@Override
public boolean evaluate() {
return person.getAge() > adultAge;
}
@Override
public void execute() {
person.setAdult(true);
System.out.printf("Person %s has been marked as adult",
person.getName());
}
@Override
public int getAdultAge() {
return adultAge;
}
@Override
public void setAdultAge(int adultAge) {
this.adultAge = adultAge;
}
}
```
Finally, let's suspend the program to change the legal adult age value at runtime via any compliant JMX client and see the engine behavior after this change:
```java
public class Launcher {
public static void main(String[] args) {
//create a person instance
Person tom = new Person("Tom", 14);
System.out.println("Tom:
Hi! can I have some Vodka please?");
//create a Jmx rules engine
JmxRulesEngine rulesEngine = aNewJmxRulesEngine()
.named("shop rules engine")
.build();
//register rules
rulesEngine.registerJmxRule(new AgeRule(tom));
rulesEngine.registerRule(new AlcoholRule(tom));
//fire rules
rulesEngine.fireRules();
// Update adult age via a JMX client.
Scanner scanner = new Scanner(System.in);
System.out.println("Change adult age via a JMX client
and then press enter");
scanner.nextLine();
System.out.println("Re fire rules after
updating adult age...");
rulesEngine.fireRules();
}
}
```
To run the second part of the tutorial, run the following command:
{% highlight bash %}
$ mvn exec:java -P runShopTutorialPart2
{% endhighlight %}
You will be asked to change the legal adult age via a JMX compliant client.
In the next screenshot, we use <a href="https://visualvm.java.net" target="_blank">VisualVM</a> to change the age value:
<img style="width: 100%" src="{{site.url}}/img/jmx.png">
If you change the age value to 13 for example, you will see that Tom will be able to buy alcohol since his age (14) is greater than the new legal adult age (13).
That's all! In this tutorial, we have seen how to create a real business rule with Easy Rules and how to reconfigure it at runtime.

@ -1,8 +1,8 @@
---
layout: docs
title: Using Easy Rules with Spring
header: Using Easy Rules with Spring
prev_section: tutorials/scheduling-engine
title: Spring tutorial
header: Spring tutorial
prev_section: tutorials/scheduler-tutorial
next_section: get-involved/release-notes
doc: true
---
@ -52,7 +52,8 @@ Now, we we can use the `RulesEngineFactoryBean` to configure a rules engine and
<bean id="rule" class="org.easyrules.samples.spring.DummyRule"/>
<!-- configure rules engine -->
<bean id="rulesEngine" class="org.easyrules.spring.RulesEngineFactoryBean">
<bean id="rulesEngine"
class="org.easyrules.spring.RulesEngineFactoryBean">
<property name="rules">
<list>
<ref bean="rule"/>
@ -89,9 +90,6 @@ $ mvn exec:java -P runSpringTutorial
You would get the following output:
```
INFO: Rule priority threshold: 2,147,483,647
INFO: Skip on first applied rule: false
INFO: Skip on first failed rule: false
INFO: Rule 'dummy rule' triggered.
Hey, I'm managed by Spring
INFO: Rule 'dummy rule' performed successfully.

@ -3,7 +3,7 @@ layout: docs
title: Defining rules
header: Defining rules
prev_section: user-guide/introduction
next_section: user-guide/rules-engine
next_section: user-guide/rule-listener
doc: true
---
@ -20,7 +20,7 @@ public interface Rule {
/**
* This method encapsulates the rule's actions.
* @throws Exception thrown if an exception occurs
* @throws Exception if an error occurs
* during actions performing
*/
void execute() throws Exception;
@ -102,7 +102,7 @@ The `@Action` annotation marks methods to execute to perform rule actions. Rules
<div class="note info">
<h5>Actions can be executed in a specified order</h5>
<p>You can also define the execution order of actions with the
<em>order</em> attribute: <em>@Action(order = 1)</em>. By default, the order of an action is 0.</p>
<em>order</em> attribute:<br/><em>@Action(order = 1)</em><br/>By default, the order of an action is 0.</p>
</div>
@ -113,7 +113,7 @@ Easy Rules allows you to create complex rules from primitive ones. A `CompositeR
This is typically an implementation of the <a href="http://en.wikipedia.org/wiki/Composite_pattern" target="_blank">composite design pattern</a>.
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 in the natural order of
When a composite rule is applied, actions of **_all_** composing rules are performed in the **natural order** of
rules which is rules priorities by default.
To create a composite rule from two primitive rules, you can use the following snippet:
@ -141,35 +141,3 @@ the `getPriority()` method
* If your rule is a annotated POJO, you should annotate the method that provides priority with `@Priority` annotation.
This method must be public, have no arguments and return an Integer type
## Rule listener
You can listen to rule execution events through the `RuleListener` API:
```java
public interface RuleListener {
/**
* Triggered before a rule is executed.
*/
void beforeExecute(Rule rule);
/**
* Triggered after a rule is executed successfully.
*/
void onSuccess(Rule rule);
/**
* Triggered after a rule is executed with error.
*/
void onFailure(Rule rule, Exception exception);
}
```
You can implement this interface to provide custom behavior to execute before/after each rule.
To register your listener, use the following snippet:
```java
RulesEngine rulesEngine = aNewRulesEngine()
.withRuleListener(myRuleListener)
.build();
```
You can register as many listeners as you want, they will be executed in their registration order.

@ -3,13 +3,13 @@ layout: docs
title: Embedding rules engine
header: Embedding rules engine
prev_section: user-guide/scheduling-rules-engine
next_section: tutorials/hello-world
next_section: tutorials/hello-world-tutorial
doc: true
---
Easy Rules is a lightweight library that can be used in a standalone Java application or embedded in a web server or a dependency injection container.
As of version {{ site.version }}, Easy Rules provides support for <a href="http://www.spring.io" target="_blank">Spring</a>.
As of version 2.1.0, Easy Rules provides support for <a href="http://www.spring.io" target="_blank">Spring</a>.
Support for other DI containers will be added in future versions.
In this section, you will learn how to configure rules and rules engine as Spring beans.
@ -87,5 +87,13 @@ rulesEngine.fireRules();
without recompiling your application.</p>
</div>
You can find a complete tutorial on how to use Easy Rules with Spring [here]({{site.url}}/tutorials/spring-tutorial.html).
You can find a complete tutorial on how to use Easy Rules with Spring [here]({{site.url}}/tutorials/spring-tutorial.html).
# Using the @SpringRule annotation
The `@SpringRule` annotation is a meta-annotation that turns a POJO into:
* A rule compatible with Easy Rules
* A **prototype-scoped** Spring bean
This annotation is the combination of `@Rule` and `@Component` annotations.

@ -28,7 +28,7 @@ To make your rule manageable via JMX, it should:
* implement the `JmxRule` interface or extend the `BasicJmxRule` class
* or be annotated with `javax.management.MXBean` if it is a annotated POJO
Once you defined your rule as a Jmx Compliant object, you can register it in a `JmxRulesEngine` as a managed rule:
Once you defined your rule as a Jmx compliant object, you can register it in a `JmxRulesEngine` as a managed rule:
```java
JmxRulesEngine rulesEngine = aNewJmxRulesEngine.build();
@ -39,4 +39,4 @@ This will register your rule as a JMX managed bean with the following object nam
`org.easyrules.core.jmx:type=YourRuleClassName,name=YourRuleName`
An example of using dynamic rule reconfiguration at runtime is provided in the [online shop tutorial]({{site.url}}/tutorials/dynamic-configuration.html).
An example of using dynamic rule reconfiguration at runtime is provided in the [shop tutorial]({{site.url}}/tutorials/shop-tutorial.html).

@ -0,0 +1,38 @@
---
layout: docs
title: Rule listener
header: Rule listener
prev_section: user-guide/defining-rules
next_section: user-guide/rules-engine
doc: true
---
You can listen to rule execution events through the `RuleListener` API:
```java
public interface RuleListener {
/**
* Triggered before a rule is executed.
*/
void beforeExecute(Rule rule);
/**
* Triggered after a rule is executed successfully.
*/
void onSuccess(Rule rule);
/**
* Triggered after a rule is executed with error.
*/
void onFailure(Rule rule, Exception exception);
}
```
You can implement this interface to provide custom behavior to execute before/after each rule.
To register your listener, use the following snippet:
```java
RulesEngine rulesEngine = aNewRulesEngine()
.withRuleListener(myRuleListener)
.build();
```
You can register as many listeners as you want, they will be executed in their registration order.

@ -67,13 +67,13 @@ Easy Rules engine can be configured with the following parameters:
</tbody>
</table>
The `skipOnFirstAppliedRule` parameter tells the engine to skip next rules when a rule is applied.
* The `skipOnFirstAppliedRule` parameter tells the engine to skip next rules when a rule is applied.
The `skipOnFirstFailedRule` parameter tells the engine to skip next rules when a rule fails.
* The `skipOnFirstFailedRule` parameter tells the engine to skip next rules when a rule fails.
The `rulePriorityThreshold` parameter tells the engine to skip next rules if priority exceeds the defined threshold.
* The `rulePriorityThreshold` parameter tells the engine to skip next rules if priority exceeds the defined threshold.
Silent mode allows you to mute all loggers when needed.
* The `silentMode` allows you to mute all loggers when needed.
You can specify these parameters through the `RulesEngineBuilder` API:
@ -84,4 +84,13 @@ RulesEngine rulesEngine = aNewRulesEngine()
.withSkipOnFirstFailedRule(true)
.withSilentMode(true)
.build();
```
```
All parameters are encapsulated in the `RulesEngineParameters` class. If you want to get parameters from your engine,
you can use the following snippet:
```java
RulesEngineParameters parameters = myEngine.getParameters();
```
This allows you to reset the engine parameters after its creation.

@ -1,7 +1,7 @@
---
layout: docs
title: Scheduling rules engine
header: Scheduling rules engine
header: Scheduling a rules engine
prev_section: user-guide/managing-rules
next_section: user-guide/embedding-rules-engine
doc: true
@ -45,4 +45,4 @@ To unregister a rules engine, use the following snippet:
scheduler.unschedule(rulesEngine);
```
You can find a tutorial about scheduling rules engine in the [time tutorial]({{site.url}}/tutorials/scheduling-engine.html).
You can find a tutorial about scheduling rules engine in the [Scheduler tutorial]({{site.url}}/tutorials/scheduler-tutorial.html).

Loading…
Cancel
Save