add new site for documentation
parent
9fa82c6ea2
commit
5cb26cb163
@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Diagram>
|
||||
<ID>JAVA</ID>
|
||||
<OriginalElement>net.benas.easyrules.core.BasicRule</OriginalElement>
|
||||
<nodes>
|
||||
<node x="655.0" y="279.0">net.benas.easyrules.core.CompositeRule</node>
|
||||
<node x="347.5" y="463.0">java.lang.Comparable</node>
|
||||
<node x="249.0" y="238.5">net.benas.easyrules.core.BasicRule</node>
|
||||
<node x="26.5" y="126.0">net.benas.easyrules.api.JmxManagedRule</node>
|
||||
<node x="277.0" y="74.5">net.benas.easyrules.api.Rule</node>
|
||||
<node x="13.0" y="320.0">net.benas.easyrules.core.BasicJmxManagedRule</node>
|
||||
</nodes>
|
||||
<notes />
|
||||
<edges>
|
||||
<edge source="net.benas.easyrules.core.BasicRule" target="java.lang.Comparable">
|
||||
<point x="0.0" y="-94.5" />
|
||||
<point x="0.0" y="24.0" />
|
||||
</edge>
|
||||
<edge source="net.benas.easyrules.core.BasicJmxManagedRule" target="net.benas.easyrules.core.BasicRule">
|
||||
<point x="82.0" y="-0.0" />
|
||||
<point x="-168.0" y="-0.0" />
|
||||
</edge>
|
||||
<edge source="net.benas.easyrules.core.BasicJmxManagedRule" target="net.benas.easyrules.api.JmxManagedRule">
|
||||
<point x="0.0" y="14.0" />
|
||||
<point x="0.0" y="-14.0" />
|
||||
</edge>
|
||||
<edge source="net.benas.easyrules.core.CompositeRule" target="net.benas.easyrules.api.Rule">
|
||||
<point x="0.0" y="0.0" />
|
||||
<point x="0.0" y="0.0" />
|
||||
</edge>
|
||||
<edge source="net.benas.easyrules.api.JmxManagedRule" target="net.benas.easyrules.api.Rule">
|
||||
<point x="67.5" y="-0.0" />
|
||||
<point x="-138.0" y="-0.0" />
|
||||
</edge>
|
||||
<edge source="net.benas.easyrules.core.BasicRule" target="net.benas.easyrules.api.Rule">
|
||||
<point x="0.0" y="94.5" />
|
||||
<point x="0.0" y="-64.5" />
|
||||
</edge>
|
||||
<edge source="net.benas.easyrules.core.CompositeRule" target="net.benas.easyrules.core.BasicRule">
|
||||
<point x="-128.0" y="-0.0" />
|
||||
<point x="168.0" y="-0.0" />
|
||||
</edge>
|
||||
</edges>
|
||||
<settings layout="Hierarchic Group" zoom="1.0" x="474.0" y="293.0" />
|
||||
<SelectedNodes />
|
||||
<Categories>
|
||||
<Category>Methods</Category>
|
||||
<Category>Inner Classes</Category>
|
||||
<Category>Properties</Category>
|
||||
</Categories>
|
||||
<SCOPE>All</SCOPE>
|
||||
<VISIBILITY>private</VISIBILITY>
|
||||
</Diagram>
|
||||
|
@ -1,34 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Diagram>
|
||||
<ID>JAVA</ID>
|
||||
<OriginalElement>net.benas.easyrules.core.DefaultRulesEngine</OriginalElement>
|
||||
<nodes>
|
||||
<node x="0.0" y="0.0">net.benas.easyrules.api.RulesEngine</node>
|
||||
<node x="145.25" y="239.0">net.benas.easyrules.core.DefaultRulesEngine</node>
|
||||
<node x="325.0" y="30.0">net.benas.easyrules.api.Rule</node>
|
||||
</nodes>
|
||||
<notes />
|
||||
<edges>
|
||||
<edge source="net.benas.easyrules.core.DefaultRulesEngine" target="net.benas.easyrules.api.Rule">
|
||||
<point x="0.0" y="0.0" />
|
||||
<point x="0.0" y="0.0" />
|
||||
</edge>
|
||||
<edge source="net.benas.easyrules.core.DefaultRulesEngine" target="net.benas.easyrules.api.RulesEngine">
|
||||
<point x="-81.25" y="-104.5" />
|
||||
<point x="226.5" y="214.0" />
|
||||
<point x="152.5" y="214.0" />
|
||||
<point x="0.0" y="94.5" />
|
||||
</edge>
|
||||
</edges>
|
||||
<settings layout="Hierarchic Group" zoom="1.0" x="301.0" y="224.0" />
|
||||
<SelectedNodes>
|
||||
<node>net.benas.easyrules.core.DefaultRulesEngine</node>
|
||||
</SelectedNodes>
|
||||
<Categories>
|
||||
<Category>Methods</Category>
|
||||
<Category>Properties</Category>
|
||||
</Categories>
|
||||
<SCOPE>All</SCOPE>
|
||||
<VISIBILITY>private</VISIBILITY>
|
||||
</Diagram>
|
||||
|
@ -0,0 +1 @@
|
||||
www.easyrules.org
|
@ -0,0 +1 @@
|
||||
Easy Rules website.
|
@ -0,0 +1,20 @@
|
||||
version: 1.1.0
|
||||
highlighter: pygments
|
||||
url: http://www.easyrules.org
|
||||
google_analytics_id: UA-46301888-1
|
||||
exclude: ["CNAME", "README"]
|
||||
|
||||
author :
|
||||
name : Mahmoud Ben Hassine
|
||||
email : md.benhassine@gmail.com
|
||||
github : benas
|
||||
twitter : md_benhassine
|
||||
web : http://www.mahmoudbenhassine.com
|
||||
|
||||
project:
|
||||
name: Easy Rules
|
||||
github: easy-rules
|
||||
|
||||
markdown: redcarpet
|
||||
redcarpet:
|
||||
extensions: ["no_intra_emphasis", "fenced_code_blocks", "autolink", "strikethrough", "superscript", "with_toc_data"]
|
@ -0,0 +1,10 @@
|
||||
<script type="text/javascript">
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', '{{ site.google_analytics_id }}']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
@ -0,0 +1 @@
|
||||
</html>
|
@ -0,0 +1,53 @@
|
||||
<div class="unit one-fifth">
|
||||
<aside>
|
||||
|
||||
<h4>About Easy Rules</h4>
|
||||
<ul>
|
||||
<li class="{% if page.title == "Overview" %}current{% endif %}">
|
||||
<a href="{{ site.url }}/about/overview.html">Overview</a>
|
||||
</li>
|
||||
<li class="{% if page.title == "Getting started" %}current{% endif %}">
|
||||
<a href="{{ site.url }}/about/getting-started.html">Getting started</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>User guide</h4>
|
||||
<ul>
|
||||
<li class="{% if page.title == "Introduction" %}current{% endif %}">
|
||||
<a href="{{ site.url }}/user-guide/introduction.html">Introduction</a>
|
||||
</li>
|
||||
<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 == "Rules engine" %}current{% endif %}">
|
||||
<a href="{{ site.url }}/user-guide/rules-engine.html">Rules engine</a>
|
||||
</li>
|
||||
<li class="{% if page.title == "Managing rules" %}current{% endif %}">
|
||||
<a href="{{ site.url }}/user-guide/managing-rules.html">Managing rules</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 == "Dynamic configuration" %}current{% endif %}">
|
||||
<a href="{{ site.url }}/tutorials/dynamic-configuration.html">Dynamic configuration</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<h4>Get involved</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<a target="_blank" href="https://github.com/benas/easy-rules">Source repository</a>
|
||||
</li>
|
||||
<li>
|
||||
<a target="_blank" href="https://github.com/benas/easy-rules/issues">Issue tracker</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</aside>
|
||||
</div>
|
@ -0,0 +1,13 @@
|
||||
<footer>
|
||||
<div class="grid">
|
||||
<div class="unit one-third center-on-mobiles">
|
||||
<p>Project created and maintained by <a target="_blank" href="{{ site.author.web }}">{{ site.author.name}}</a>.</p>
|
||||
</div>
|
||||
<div class="unit two-thirds align-right center-on-mobiles">
|
||||
<p>
|
||||
Inspired by and built with <a target="_blank" href="http://jekyllrb.com">Jekyll</a>. Hosted on <a target="_blank" href="https://github.com">Github</a>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
@ -0,0 +1,14 @@
|
||||
<header>
|
||||
<div class="grid">
|
||||
<div class="unit one-third">
|
||||
<a href="{{ site.url }}/index.html">
|
||||
<h1>
|
||||
<span class="shadow">{{ site.project.name }}</span>
|
||||
</h1>
|
||||
</a>
|
||||
</div>
|
||||
<nav class="main-nav unit two-thirds">
|
||||
{% include primary-nav-items.html %}
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
@ -0,0 +1,12 @@
|
||||
<ul>
|
||||
<li> </li>
|
||||
<li class="{% if page.overview %}current{% endif %}">
|
||||
<a href="{{ site.url }}/index.html">Home</a>
|
||||
</li>
|
||||
<li class="{% if page.doc %}current{% endif %}">
|
||||
<a href="{{ site.url }}/about/overview.html">Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a target="_blank" href="https://github.com/{{ site.author.github }}/{{ site.project.github }}">View on GitHub</a>
|
||||
</li>
|
||||
</ul>
|
@ -0,0 +1,22 @@
|
||||
<div class="section-nav">
|
||||
<div class="left align-right">
|
||||
{% if page.prev_section != null %}
|
||||
<a href="{{ site.url }}/{{ page.prev_section }}.html" class="prev">
|
||||
Back
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="prev disabled">Back</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="right align-left">
|
||||
{% if page.next_section != null %}
|
||||
<a href="{{ site.url }}/{{ page.next_section }}.html" class="next">
|
||||
Next
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="next disabled">Next</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
|
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{ page.title }}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link href='http://fonts.googleapis.com/css?family=Lato:100,300,400,700,900,100italic,300italic,400italic,700italic,900italic' rel='stylesheet' type='text/css'>
|
||||
<link href='http://fonts.googleapis.com/css?family=Arizonia' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" href="{{ site.url }}/css/normalize.css" />
|
||||
<link rel="stylesheet" href="{{ site.url }}/css/gridism.css" />
|
||||
<link rel="stylesheet" href="{{ site.url }}/css/style.css" />
|
||||
<link rel="stylesheet" href="{{ site.url }}/css/pygments.css" />
|
||||
<link rel="icon" type="image/x-icon" href="{{ site.url }}/favicon.ico" />
|
||||
<script src="{{ site.url }}/js/modernizr-2.5.3.min.js"></script>
|
||||
</head>
|
@ -0,0 +1,16 @@
|
||||
{% include top.html %}
|
||||
|
||||
<body class="wrap">
|
||||
|
||||
{% include header.html %}
|
||||
|
||||
{{ content }}
|
||||
|
||||
{% include footer.html %}
|
||||
|
||||
{% include analytics.html %}
|
||||
|
||||
</body>
|
||||
|
||||
{% include bottom.html %}
|
||||
|
@ -0,0 +1,21 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
<section class="docs">
|
||||
<div class="grid">
|
||||
|
||||
<div class="unit four-fifths">
|
||||
<article>
|
||||
<h1>{{ page.header }}</h1>
|
||||
{{ content }}
|
||||
{% include section_nav.html %}
|
||||
</article>
|
||||
</div>
|
||||
|
||||
{% include docs_contents.html %}
|
||||
|
||||
<div class="clear"></div>
|
||||
|
||||
</div>
|
||||
</section>
|
@ -0,0 +1,41 @@
|
||||
---
|
||||
layout: docs
|
||||
title: Getting started
|
||||
header: Getting started
|
||||
prev_section: about/overview
|
||||
next_section: user-guide/introduction
|
||||
doc: true
|
||||
---
|
||||
|
||||
Easy Rules is a Java library. It requires a Java 1.5+ runtime.
|
||||
|
||||
## Building form source
|
||||
|
||||
To build Easy Rules from sources, you need to have [git](http://www.git-scm.com) and [maven](http://maven.apache.org/) installed and set up.
|
||||
|
||||
Please follow these instructions :
|
||||
|
||||
{% highlight bash %}
|
||||
$ git clone https://github.com/benas/easy-rules.git
|
||||
$ mvn package
|
||||
{% endhighlight %}
|
||||
|
||||
Easy Rules core jar **_easyrules-core-${version}.jar_** will be generated in the target folder.
|
||||
|
||||
## Use with maven
|
||||
|
||||
Easy Rules is a single jar file with no dependencies. You have to simply add the jar **_easyrules-core-{{site.version}}.jar_** to your application's classpath.
|
||||
|
||||
Using maven, you should add the following dependency to your pom.xml :
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.easyrules</groupId>
|
||||
<artifactId>easyrules-core</artifactId>
|
||||
<version>{{site.version}}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
---
|
||||
layout: docs
|
||||
title: Overview
|
||||
header: What is Easy rules?
|
||||
next_section: about/getting-started
|
||||
doc: true
|
||||
---
|
||||
|
||||
Easy Rules is a simple yet powerful Java rules engine providing the following features:
|
||||
|
||||
* Lightweight framework and easy to learn API
|
||||
* POJO based development
|
||||
* Useful abstractions to define business rules and apply them easily
|
||||
* The ability to create composite rules from primitive ones
|
||||
* Dynamic rule configuration at runtime using JMX
|
||||
|
||||
In a very interesting [article](http://martinfowler.com/bliki/RulesEngine.html) about rules engines, [Martin Fowler](http://martinfowler.com/) says the following :
|
||||
|
||||
>You can build a simple rules engine yourself. All you need is to create a bunch of objects with conditions and actions, store them in a collection, and run through them to evaluate the conditions and execute the actions.
|
||||
|
||||
This is exactly what Easy Rules does, with more features like rule composition and dynamic configuration.
|
@ -0,0 +1,504 @@
|
||||
/*! normalize.css 2012-03-11T12:53 UTC - http://github.com/necolas/normalize.css */
|
||||
|
||||
/* =============================================================================
|
||||
HTML5 display definitions
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Corrects block display not defined in IE6/7/8/9 & FF3
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Corrects inline-block display not defined in IE6/7/8/9 & FF3
|
||||
*/
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
video {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevents modern browsers from displaying 'audio' without controls
|
||||
* Remove excess height in iOS5 devices
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses styling for 'hidden' attribute not present in IE7/8/9, FF3, S4
|
||||
* Known issue: no IE6 support
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
Base
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* 1. Corrects text resizing oddly in IE6/7 when body font-size is set using em units
|
||||
* http://clagnut.com/blog/348/#c790
|
||||
* 2. Prevents iOS text size adjust after orientation change, without disabling user zoom
|
||||
* www.456bereastreet.com/archive/201012/controlling_text_size_in_safari_for_ios_without_disabling_user_zoom/
|
||||
*/
|
||||
|
||||
html {
|
||||
font-size: 100%; /* 1 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses font-family inconsistency between 'textarea' and other form elements.
|
||||
*/
|
||||
|
||||
html,
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses margins handled incorrectly in IE6/7
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
Links
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Addresses outline displayed oddly in Chrome
|
||||
*/
|
||||
|
||||
a:focus {
|
||||
outline: thin dotted;
|
||||
}
|
||||
|
||||
/*
|
||||
* Improves readability when focused and also mouse hovered in all browsers
|
||||
* people.opera.com/patrickl/experiments/keyboard/test
|
||||
*/
|
||||
|
||||
a:hover,
|
||||
a:active {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
Typography
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Addresses font sizes and margins set differently in IE6/7
|
||||
* Addresses font sizes within 'section' and 'article' in FF4+, Chrome, S5
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
margin: 0.83em 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.17em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1em;
|
||||
margin: 1.33em 0;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 0.83em;
|
||||
margin: 1.67em 0;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 0.75em;
|
||||
margin: 2.33em 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses styling not present in IE7/8/9, S5, Chrome
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses style set to 'bolder' in FF3+, S4/5, Chrome
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses styling not present in S5, Chrome
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses styling not present in IE6/7/8/9
|
||||
*/
|
||||
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses margins set differently in IE6/7
|
||||
*/
|
||||
|
||||
p,
|
||||
pre {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Corrects font family set oddly in IE6, S4/5, Chrome
|
||||
* en.wikipedia.org/wiki/User:Davidgothberg/Test59
|
||||
*/
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, serif;
|
||||
_font-family: 'courier new', monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Improves readability of pre-formatted text in all browsers
|
||||
*/
|
||||
|
||||
pre {
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Addresses CSS quotes not supported in IE6/7
|
||||
* 2. Addresses quote property not supported in S4
|
||||
*/
|
||||
|
||||
/* 1 */
|
||||
|
||||
q {
|
||||
quotes: none;
|
||||
}
|
||||
|
||||
/* 2 */
|
||||
|
||||
q:before,
|
||||
q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevents sub and sup affecting line-height in all browsers
|
||||
* gist.github.com/413930
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
Lists
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Addresses margins set differently in IE6/7
|
||||
*/
|
||||
|
||||
dl,
|
||||
menu,
|
||||
ol,
|
||||
ul {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin: 0 0 0 40px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses paddings set differently in IE6/7
|
||||
*/
|
||||
|
||||
menu,
|
||||
ol,
|
||||
ul {
|
||||
padding: 0 0 0 40px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Corrects list images handled incorrectly in IE7
|
||||
*/
|
||||
|
||||
nav ul,
|
||||
nav ol {
|
||||
list-style: none;
|
||||
list-style-image: none;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* 1. Removes border when inside 'a' element in IE6/7/8/9, FF3
|
||||
* 2. Improves image quality when scaled in IE7
|
||||
* code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/
|
||||
*/
|
||||
|
||||
img {
|
||||
border: 0; /* 1 */
|
||||
-ms-interpolation-mode: bicubic; /* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Corrects overflow displayed oddly in IE9
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
Figures
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Addresses margin not present in IE6/7/8/9, S5, O11
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
Forms
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Corrects margin displayed oddly in IE6/7
|
||||
*/
|
||||
|
||||
form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Define consistent border, margin, and padding
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Corrects color not being inherited in IE6/7/8/9
|
||||
* 2. Corrects text not wrapping in FF3
|
||||
* 3. Corrects alignment displayed oddly in IE6/7
|
||||
*/
|
||||
|
||||
legend {
|
||||
border: 0; /* 1 */
|
||||
padding: 0;
|
||||
white-space: normal; /* 2 */
|
||||
*margin-left: -7px; /* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Corrects font size not being inherited in all browsers
|
||||
* 2. Addresses margins set differently in IE6/7, FF3+, S5, Chrome
|
||||
* 3. Improves appearance and consistency in all browsers
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-size: 100%; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
vertical-align: baseline; /* 3 */
|
||||
*vertical-align: middle; /* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses FF3/4 setting line-height on 'input' using !important in the UA stylesheet
|
||||
*/
|
||||
|
||||
button,
|
||||
input {
|
||||
line-height: normal; /* 1 */
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Improves usability and consistency of cursor style between image-type 'input' and others
|
||||
* 2. Corrects inability to style clickable 'input' types in iOS
|
||||
* 3. Removes inner spacing in IE7 without affecting normal text inputs
|
||||
* Known issue: inner spacing remains in IE6
|
||||
*/
|
||||
|
||||
button,
|
||||
input[type="button"],
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
cursor: pointer; /* 1 */
|
||||
-webkit-appearance: button; /* 2 */
|
||||
*overflow: visible; /* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-set default cursor for disabled elements
|
||||
*/
|
||||
|
||||
button[disabled],
|
||||
input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Addresses box sizing set to content-box in IE8/9
|
||||
* 2. Removes excess padding in IE8/9
|
||||
* 3. Removes excess padding in IE7
|
||||
Known issue: excess padding remains in IE6
|
||||
*/
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
*height: 13px; /* 3 */
|
||||
*width: 13px; /* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Addresses appearance set to searchfield in S5, Chrome
|
||||
* 2. Addresses box-sizing set to border-box in S5, Chrome (include -moz to future-proof)
|
||||
*/
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box; /* 2 */
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes inner padding and search cancel button in S5, Chrome on OS X
|
||||
*/
|
||||
|
||||
input[type="search"]::-webkit-search-decoration,
|
||||
input[type="search"]::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes inner padding and border in FF3+
|
||||
* www.sitepen.com/blog/2008/05/14/the-devils-in-the-details-fixing-dojos-toolbar-buttons/
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Removes default vertical scrollbar in IE6/7/8/9
|
||||
* 2. Improves readability and alignment in all browsers
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto; /* 1 */
|
||||
vertical-align: top; /* 2 */
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
Tables
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Remove most spacing between table cells
|
||||
*/
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
.highlight .hll { background-color: #222222 }
|
||||
/* .highlight { background: #000000; color: #cccccc } */
|
||||
.highlight .c { color: #777777; font-style: italic } /* Comment */
|
||||
.highlight .err { color: #cccccc; border: 1px solid #FF0000 } /* Error */
|
||||
.highlight .g { color: #cccccc } /* Generic */
|
||||
.highlight .k { color: #cdcd00 } /* Keyword */
|
||||
.highlight .l { color: #cccccc } /* Literal */
|
||||
.highlight .n { color: #cccccc } /* Name */
|
||||
.highlight .o { color: #3399cc } /* Operator */
|
||||
.highlight .x { color: #cccccc } /* Other */
|
||||
.highlight .p { color: #cccccc } /* Punctuation */
|
||||
.highlight .cm { color: #777777; font-style: italic } /* Comment.Multiline */
|
||||
.highlight .cp { color: #777777; font-style: italic } /* Comment.Preproc */
|
||||
.highlight .c1 { color: #777777; font-style: italic } /* Comment.Single */
|
||||
.highlight .cs { color: #cd5c5c; font-weight: bold } /* Comment.Special */
|
||||
.highlight .gd { color: #cd5c5c } /* Generic.Deleted */
|
||||
.highlight .ge { color: #cccccc; font-style: italic } /* Generic.Emph */
|
||||
.highlight .gr { color: #FF0000 } /* Generic.Error */
|
||||
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||
.highlight .gi { color: #00cd00 } /* Generic.Inserted */
|
||||
.highlight .go { color: #888888 } /* Generic.Output */
|
||||
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
||||
.highlight .gs { color: #cccccc; font-weight: bold } /* Generic.Strong */
|
||||
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||
.highlight .gt { color: #0044DD } /* Generic.Traceback */
|
||||
.highlight .kc { color: #cdcd00 } /* Keyword.Constant */
|
||||
.highlight .kd { color: #00cd00 } /* Keyword.Declaration */
|
||||
.highlight .kn { color: #cd00cd } /* Keyword.Namespace */
|
||||
.highlight .kp { color: #cdcd00 } /* Keyword.Pseudo */
|
||||
.highlight .kr { color: #cdcd00 } /* Keyword.Reserved */
|
||||
.highlight .kt { color: #00cd00 } /* Keyword.Type */
|
||||
.highlight .ld { color: #cccccc } /* Literal.Date */
|
||||
.highlight .m { color: #cd00cd } /* Literal.Number */
|
||||
.highlight .s { color: #cd5c5c } /* Literal.String */
|
||||
.highlight .na { color: #008080 } /* Name.Attribute */
|
||||
.highlight .nb { color: #cd00cd } /* Name.Builtin */
|
||||
.highlight .nc { color: #00cdcd } /* Name.Class */
|
||||
.highlight .no { color: #cccccc } /* Name.Constant */
|
||||
.highlight .nd { color: #cccc00 } /* Name.Decorator */
|
||||
.highlight .ni { color: #cccccc } /* Name.Entity */
|
||||
.highlight .ne { color: #666699; font-weight: bold } /* Name.Exception */
|
||||
.highlight .nf { color: #f0e68c } /* Name.Function */
|
||||
.highlight .nl { color: #cccccc } /* Name.Label */
|
||||
.highlight .nn { color: #cccccc } /* Name.Namespace */
|
||||
.highlight .nx { color: #cccccc } /* Name.Other */
|
||||
.highlight .py { color: #cccccc } /* Name.Property */
|
||||
.highlight .nt { color: #00cccc } /* Name.Tag */
|
||||
.highlight .nv { color: #00cdcd } /* Name.Variable */
|
||||
.highlight .ow { color: #cdcd00 } /* Operator.Word */
|
||||
.highlight .w { color: #cccccc } /* Text.Whitespace */
|
||||
.highlight .mf { color: #cd00cd } /* Literal.Number.Float */
|
||||
.highlight .mh { color: #cd00cd } /* Literal.Number.Hex */
|
||||
.highlight .mi { color: #cd00cd } /* Literal.Number.Integer */
|
||||
.highlight .mo { color: #cd00cd } /* Literal.Number.Oct */
|
||||
.highlight .sb { color: #cd5c5c } /* Literal.String.Backtick */
|
||||
.highlight .sc { color: #cd5c5c } /* Literal.String.Char */
|
||||
.highlight .sd { color: #cd5c5c } /* Literal.String.Doc */
|
||||
.highlight .s2 { color: #cd5c5c } /* Literal.String.Double */
|
||||
.highlight .se { color: #cd5c5c } /* Literal.String.Escape */
|
||||
.highlight .sh { color: #cd5c5c } /* Literal.String.Heredoc */
|
||||
.highlight .si { color: #cd5c5c } /* Literal.String.Interpol */
|
||||
.highlight .sx { color: #cd5c5c } /* Literal.String.Other */
|
||||
.highlight .sr { color: #cd5c5c } /* Literal.String.Regex */
|
||||
.highlight .s1 { color: #cd5c5c } /* Literal.String.Single */
|
||||
.highlight .ss { color: #cd5c5c } /* Literal.String.Symbol */
|
||||
.highlight .bp { color: #cd00cd } /* Name.Builtin.Pseudo */
|
||||
.highlight .vc { color: #00cdcd } /* Name.Variable.Class */
|
||||
.highlight .vg { color: #00cdcd } /* Name.Variable.Global */
|
||||
.highlight .vi { color: #00cdcd } /* Name.Variable.Instance */
|
||||
.highlight .il { color: #cd00cd } /* Literal.Number.Integer.Long */
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
@ -0,0 +1,95 @@
|
||||
---
|
||||
layout: default
|
||||
title: Easy rules • Xml-free open source Java™ rules engine.
|
||||
overview: true
|
||||
---
|
||||
|
||||
<section class="intro">
|
||||
<div class="grid">
|
||||
<div class="unit whole">
|
||||
<p class="first">Xml-free open source Java™ rules engine.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="features">
|
||||
<div class="grid">
|
||||
<div class="unit one-third">
|
||||
<h2>Lightweight</h2>
|
||||
<p>
|
||||
A tiny jar with no dependencies and a lot of features!
|
||||
</p>
|
||||
<a href="{{ site.url }}/about/getting-started.html" class="">Get started →</a>
|
||||
</div>
|
||||
<div class="unit one-third">
|
||||
<h2>POJO based</h2>
|
||||
<p>
|
||||
Turn your POJOs into business rules with a couple of annotations.
|
||||
</p>
|
||||
<a href="{{ site.url }}/about/overview.html" class="">Read documentation →</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.
|
||||
</p>
|
||||
<a href="{{ site.url }}/tutorials/hello-world.html" class="">2 minutes tutorial →</a>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="quickstart">
|
||||
<div class="grid">
|
||||
<div class="unit code" style="width: 50%">
|
||||
<p class="title">Then, fire it!</p>
|
||||
<div class="shell">
|
||||
<div class="highlight"><pre><code class="language-java" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size: 16px"><span class="kd">public class</span> <span class="nc">Test</span> <span class="o">{</span>
|
||||
<span class="kd">public static void</span> <span class="nf">main</span><span class="o">(</span>String<span class="o">[]</span> args<span class="o">)</span> <span class="o">{</span>
|
||||
<span class="c1">// create a rules engine</span>
|
||||
AnnotatedRulesEngine rulesEngine <span class="o">=</span>
|
||||
<span class="k">new</span> AnnotatedRulesEngine<span class="o">();</span>
|
||||
<span class="c1">//register the rule</span>
|
||||
rulesEngine<span class="o">.</span><span class="na">registerRule</span><span class="o">(</span><span class="k">new</span> MyRule<span class="o">());</span>
|
||||
<span class="c1">//fire rules!</span>
|
||||
rulesEngine<span class="o">.</span><span class="na">fireRules</span><span class="o">();</span>
|
||||
<span class="o">}</span>
|
||||
<span class="o">}</span></code></pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="unit code" style="width: 50%">
|
||||
<p class="title">First, define your rule..</p>
|
||||
<div class="shell">
|
||||
<div class="highlight"><pre><code class="language-java" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size: 16px"><span class="nd">@Rule</span> <span class="o">(</span>name <span class="o">=</span> <span class="s">"my awesome rule"</span> <span class="o">)</span>
|
||||
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">MyRule</span> <span class="o">{</span>
|
||||
<span class="nd">@Condition</span>
|
||||
<span class="kd">public boolean</span> <span class="nf">when</span><span class="o">()</span> <span class="o">{</span>
|
||||
<span class="k">return</span> true<span class="o">;</span>
|
||||
<span class="o">}</span>
|
||||
<span class="nd">@Action</span>
|
||||
<span class="kd">public void</span> <span class="nf">then</span><span class="o">()</span> <span class="o">{</span>
|
||||
System<span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Easy Rules rocks!"</span><span class="o">);</span>
|
||||
<span class="o">}</span>
|
||||
<span class="o">}</span></code></pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="free-hosting">
|
||||
<div class="grid">
|
||||
<div class="unit whole">
|
||||
<div class="grid pane">
|
||||
<div class="unit whole center-on-mobiles">
|
||||
<div class="pane-content">
|
||||
<h2>License</h2>
|
||||
<p>Easy Rules is open source, hosted on <a target="_blank" href="https://github.com/benas/easy-rules">GitHub</a> and is released under the <a target="_blank" href="http://opensource.org/licenses/mit-license.php/">MIT License</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,206 @@
|
||||
---
|
||||
layout: docs
|
||||
title: Dynamic configuration
|
||||
header: Online shop tutorial
|
||||
prev_section: tutorials/hello-world
|
||||
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 reconfigurable 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.
|
||||
|
||||
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 evaluateConditions() {
|
||||
return order.getAmount() > suspectOrderAmountThreshold
|
||||
&& customer.isNew();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performActions() 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 omitted
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This rule operates on an order and a customer instances which represent the business data to operate on.
|
||||
|
||||
The `evaluateConditions` method evaluates to true when the customer is new and the order amount is greater than the defined threshold.
|
||||
|
||||
The `performActions` 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 an Easy Rules engine and register the `SuspectOrderRule` rule:
|
||||
|
||||
```java
|
||||
public class OrderSampleLauncher {
|
||||
|
||||
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 default rules engine and register the business rule
|
||||
*/
|
||||
DefaultRulesEngine rulesEngine = new DefaultRulesEngine();
|
||||
rulesEngine.registerRule(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 Rule {
|
||||
|
||||
/**
|
||||
* 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 OrderSampleLauncher {
|
||||
|
||||
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 default rules engine and register the business rule
|
||||
*/
|
||||
DefaultRulesEngine rulesEngine = new DefaultRulesEngine();
|
||||
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.
|
@ -0,0 +1,108 @@
|
||||
---
|
||||
layout: docs
|
||||
title: Hello World
|
||||
header: Hello World tutorial
|
||||
prev_section: user-guide/managing-rules
|
||||
next_section: tutorials/dynamic-configuration
|
||||
doc: true
|
||||
---
|
||||
|
||||
This tutorial shows how to use Easy Rules on 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'.
|
||||
|
||||
Based on this requirement, the rule is pretty straightforward :
|
||||
|
||||
* The condition is that the user input must be equal to 'yes'
|
||||
* The action is to say 'Hello duke's friend!' to the user
|
||||
|
||||
First, let's create a rule class:
|
||||
|
||||
```java
|
||||
@Rule(name = "Hello World rule",
|
||||
description = "Say Hello to only duke's friends")
|
||||
public class HelloWorldRule {
|
||||
|
||||
/**
|
||||
* The user input which represents the data
|
||||
* that the rule will operate on.
|
||||
*/
|
||||
private String input;
|
||||
|
||||
@Condition
|
||||
public boolean checkInput() {
|
||||
//The rule should be applied only if
|
||||
//the user's response is yes (duke friend)
|
||||
return input.equalsIgnoreCase("yes");
|
||||
}
|
||||
|
||||
@Action
|
||||
public void sayHelloToDukeFriend() throws Exception {
|
||||
//When rule conditions are satisfied,
|
||||
//prints 'Hello duke's friend!' to the console
|
||||
System.out.println("Hello duke's friend!");
|
||||
}
|
||||
|
||||
public void setInput(String input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Then, we have to register an instance of this rule to an Easy Rules engine and launch the program with the following class :
|
||||
|
||||
```java
|
||||
public class HelloWorldSampleLauncher {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
System.out.println("Are you a friend of duke?[yes/no]:");
|
||||
String input = scanner.nextLine();
|
||||
|
||||
/**
|
||||
* Declare the rule
|
||||
*/
|
||||
HelloWorldRule helloWorldRule = new HelloWorldRule();
|
||||
|
||||
/**
|
||||
* Set business data to operate on
|
||||
*/
|
||||
helloWorldRule.setInput(input.trim());
|
||||
|
||||
/**
|
||||
* Create a rules engine and register the business rule
|
||||
*/
|
||||
AnnotatedRulesEngine rulesEngine =
|
||||
new AnnotatedRulesEngine();
|
||||
rulesEngine.registerRule(helloWorldRule);
|
||||
|
||||
/**
|
||||
* 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 runHelloWorldTutorial
|
||||
{% endhighlight %}
|
||||
|
||||
If you run this tutorial, you would get the following output:
|
||||
|
||||
```
|
||||
Are you a friend of duke? [yes/no]:
|
||||
yes
|
||||
10 sep. 2014 13:26:19 io.github.benas.easyrules.core.DefaultRulesEngine fireRules
|
||||
INFO: Rule 'Hello World rule' triggered.
|
||||
Hello duke's friend!
|
||||
10 sep. 2014 13:26:19 io.github.benas.easyrules.core.DefaultRulesEngine fireRules
|
||||
INFO: Rule 'Hello World rule' performed successfully.
|
||||
```
|
||||
|
@ -0,0 +1,131 @@
|
||||
---
|
||||
layout: docs
|
||||
title: Defining rules
|
||||
header: Defining rules
|
||||
prev_section: user-guide/introduction
|
||||
next_section: user-guide/rules-engine
|
||||
doc: true
|
||||
---
|
||||
|
||||
The key API in Easy Rules is the `Rule` interface:
|
||||
|
||||
```java
|
||||
public interface Rule {
|
||||
|
||||
/**
|
||||
* This method encapsulates the rule's conditions.
|
||||
* @return true if the rule should be applied, false else
|
||||
*/
|
||||
boolean evaluateConditions();
|
||||
|
||||
/**
|
||||
* This method encapsulates the rule's actions.
|
||||
* @throws Exception thrown if an exception occurs
|
||||
* during actions performing
|
||||
*/
|
||||
void performActions() throws Exception;
|
||||
|
||||
//Getters and setters for rule name,
|
||||
//description and priority omitted.
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
The `evaluateConditions` method encapsulates conditions that must evaluate to _TRUE_ to trigger the rule.
|
||||
|
||||
The `performActions` method encapsulates actions that should be performed when rule's conditions are satisfied.
|
||||
|
||||
## Defining rules by extending _BasicRule_
|
||||
|
||||
Easy Rules provides a simple implementation of the `Rule` interface named `BasicRule`. This class implements most of methods
|
||||
defined in the `Rule` interface. You can extends this class and override `evaluateConditions` and
|
||||
`performActions` methods to provide your conditions and actions logic. Here is an example:
|
||||
|
||||
```java
|
||||
public class MyRule extends BasicRule {
|
||||
|
||||
private BusinessData myBusinessData; //data to operate on
|
||||
|
||||
@Override
|
||||
public boolean evaluateConditions() {
|
||||
//my rule conditions
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performActions() throws Exception {
|
||||
//my actions
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## Defining rules using annotations
|
||||
|
||||
Easy Rules provides the `@Rule` annotation that can turn a POJO into a rule. Here is an example:
|
||||
|
||||
```java
|
||||
@Rule(name = "my rule", description = "my rule description")
|
||||
public class MyRule {
|
||||
|
||||
private BusinessData myBusinessData; //data to operate on
|
||||
|
||||
@Condition
|
||||
public boolean checkConditions() {
|
||||
//my rule conditions
|
||||
return true;
|
||||
}
|
||||
|
||||
@Action
|
||||
public void performActions() throws Exception {
|
||||
//my actions
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
You can use `@Condition` and `@Action` annotations to mark methods to execute to check rule conditions and perform rule actions
|
||||
respectively.
|
||||
|
||||
<div class="note info">
|
||||
<h5>Rules can have multiple actions</h5>
|
||||
<p>You can annotate multiple methods with the <em>Action</em> annotation. You can also define the execution order of actions with the
|
||||
<em>order</em> attribute: <em>@Action(order = 1)</em>.</p>
|
||||
</div>
|
||||
|
||||
|
||||
## Composite rules
|
||||
|
||||
Easy Rules allows you to create complex rules from primitive ones. A `CompositeRule` is composed of a set of rules.
|
||||
|
||||
This is typically an implementation of the [composite design pattern](http://en.wikipedia.org/wiki/Composite_pattern).
|
||||
|
||||
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
|
||||
rules which is rules priorities by default.
|
||||
|
||||
To create a composite rule from two primitive rules, you can use the following snippet:
|
||||
|
||||
```java
|
||||
//Create the composite rule from two primitive rules
|
||||
CompositeRule myCompositeRule =
|
||||
new CompositeRule("myCompositeRule", "a composite rule");
|
||||
myCompositeRule.addRule(myRule1);
|
||||
myCompositeRule.addRule(myRule2);
|
||||
|
||||
//Register the composite rule as a regular rule
|
||||
RulesEngine rulesEngine = new DefaultRulesEngine();
|
||||
rulesEngine.registerRule(myCompositeRule);
|
||||
```
|
||||
|
||||
## Rules priorities
|
||||
|
||||
Each rule in Easy Rules has a priority. This represents the default order in which registered rules are fired.
|
||||
By default, lower values represent higher priorities.
|
||||
To override this behavior, you should override the `compareTo` method to provide a custom priority strategy.
|
||||
|
||||
* If you decided to extend the `BasicRule` class, you can specify rule priority at construction time or by overriding
|
||||
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
|
@ -0,0 +1,21 @@
|
||||
---
|
||||
layout: docs
|
||||
title: Introduction
|
||||
header: Introduction
|
||||
prev_section: about/getting-started
|
||||
next_section: user-guide/defining-rules
|
||||
doc: true
|
||||
---
|
||||
|
||||
Most business rules can be represented by the following rule definition:
|
||||
|
||||
* _Name_: a unique rule name within a rules namespace
|
||||
* _Description_: a brief description of the rule
|
||||
* _Priority_: rule priority regarding to other rules
|
||||
* _Conditions_: set of conditions that should be satisfied to apply the rule
|
||||
* _Actions_: set of actions to perform when conditions are satisfied
|
||||
|
||||
Easy Rules provides an abstraction for each of these key points that define a business rule.
|
||||
|
||||
Next section will show you how to define a rule in Easy Rules either by extending a base class or by annotating your
|
||||
own domain class.
|
@ -0,0 +1,28 @@
|
||||
---
|
||||
layout: docs
|
||||
title: Managing rules
|
||||
header: Managing rules at runtime
|
||||
prev_section: user-guide/rules-engine
|
||||
next_section: tutorials/hello-world
|
||||
doc: true
|
||||
---
|
||||
|
||||
Being able to dynamically reconfigure business rules at runtime in production systems is a recurrent requirement.
|
||||
|
||||
Thanks to JMX, Easy Rules can expose rules attributes to be managed via any JMX compliant client.
|
||||
|
||||
To make your rule manageable via JMX, you can register it in Easy Rules engine as a JMX managed rule:
|
||||
|
||||
```java
|
||||
RulesEngine rulesEngine = new DefaultRulesEngine();
|
||||
rulesEngine.registerJmxRule(myRule);
|
||||
```
|
||||
|
||||
This will register your rule as a JMX managed bean with the following object name:
|
||||
|
||||
`org.easyrules.core.jmx:type=YourRuleClassName,name=YourRuleName`
|
||||
|
||||
By default, rule description and priority are exposed as JMX manageable attributes.
|
||||
If you need to expose more specific attributes, you can extend the `Rule` interface and add getters and setters of your manageable attributes.
|
||||
|
||||
An example of using dynamic rule reconfiguration at runtime is provided in the [online shop tutorial]({{site.url}}/tutorials/dynamic-configuration.html).
|
@ -0,0 +1,75 @@
|
||||
---
|
||||
layout: docs
|
||||
title: Rules engine
|
||||
header: Rules engine
|
||||
prev_section: user-guide/defining-rules
|
||||
next_section: user-guide/managing-rules
|
||||
doc: true
|
||||
---
|
||||
|
||||
Easy Rules engine handles a registry of rules with unique names. Each instance of Easy Rules engine can be seen as a separate namespace.
|
||||
|
||||
Rules are applied according to their natural order.
|
||||
|
||||
Easy Rules engine provides the following parameters:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th>Parameter</th>
|
||||
<th>Type</th>
|
||||
<th>Required</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>skipOnFirstAppliedRule</td>
|
||||
<td>boolean</td>
|
||||
<td>no</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>rulePriorityThreshold</td>
|
||||
<td>int</td>
|
||||
<td>no</td>
|
||||
<td>Integer.MAX_VALUE</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
The `skipOnFirstAppliedRule` parameter tells the engine to skip next applicable rules when a rule is applied.
|
||||
|
||||
The `rulePriorityThreshold` parameters tells the engine to skip next rules if priority exceeds the defined threshold.
|
||||
|
||||
You can specify these parameters at rules engine construction time.
|
||||
|
||||
## Create a default rules engine
|
||||
|
||||
To create a default Easy Rules engine and register a rule, use the following snippet:
|
||||
|
||||
```java
|
||||
RulesEngine<Rule> rulesEngine = new DefaultRulesEngine();
|
||||
rulesEngine.registerRule(myRule);
|
||||
```
|
||||
|
||||
You can fire registered rules as follows:
|
||||
|
||||
```java
|
||||
rulesEngine.fireRules();
|
||||
```
|
||||
|
||||
## Create a annotated rules engine
|
||||
|
||||
If your rules are annotated POJOs, you have to use the `AnnotatedRulesEngine` to register them:
|
||||
|
||||
```java
|
||||
AnnotatedRulesEngine rulesEngine = new AnnotatedRulesEngine();
|
||||
rulesEngine.registerRule(myRule);
|
||||
```
|
||||
|
||||
As with default engine, you can fire rules using the following snippet :
|
||||
|
||||
```java
|
||||
rulesEngine.fireRules();
|
||||
```
|
Loading…
Reference in New Issue