[jboss-svn-commits] JBL Code SVN: r7875 - labs/jbossrules/trunk/documentation/manual/en/Chapter-Rule_Engine
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Tue Nov 28 09:08:57 EST 2006
Author: michael.neale at jboss.com
Date: 2006-11-28 09:08:53 -0500 (Tue, 28 Nov 2006)
New Revision: 7875
Modified:
labs/jbossrules/trunk/documentation/manual/en/Chapter-Rule_Engine/Section-The_Drools_Rule_Engine.xml
Log:
section on truth maintenance
Modified: labs/jbossrules/trunk/documentation/manual/en/Chapter-Rule_Engine/Section-The_Drools_Rule_Engine.xml
===================================================================
--- labs/jbossrules/trunk/documentation/manual/en/Chapter-Rule_Engine/Section-The_Drools_Rule_Engine.xml 2006-11-28 14:08:39 UTC (rev 7874)
+++ labs/jbossrules/trunk/documentation/manual/en/Chapter-Rule_Engine/Section-The_Drools_Rule_Engine.xml 2006-11-28 14:08:53 UTC (rev 7875)
@@ -8,14 +8,14 @@
<para>Drools is split into two main parts: Authoring and Runtime.</para>
<para>The authoring process involves the creation of DRL or XML files for
- rules which are fed into a parser - defined by an Antlr 3 grammer. The
- parser checks for correctly formed grammer and produces an
- intermediate structure for the "descr"; where the "descr" indicates the AST that
+ rules which are fed into a parser - defined by an Antlr 3 grammer. The
+ parser checks for correctly formed grammer and produces an intermediate
+ structure for the "descr"; where the "descr" indicates the AST that
"describes" the rules. The AST is then passed to the Package Builder which
produces Packages. Package Builder also undertakes any code generation and
compilation that is necessary for the creation of the Pacakge. A Packge
- object is self contained and deployeable, in that it's a serialized
- object consisting of one or more rules.</para>
+ object is self contained and deployeable, in that it's a serialized object
+ consisting of one or more rules.</para>
<figure>
<title>Authoring Components</title>
@@ -32,13 +32,14 @@
</figure>
<para>A RuleBase is a runtime component which consists of one or more
- Packages. Packages can be added and removed from the RuleBase at any
- time. A RuleBase can instantiate one or more WorkingMemories at any time;
- a weak reference is maintained, unless configured otherwise. The Working
- Memory consists of a number of sub components, inculding Working Memory
- Event Support, Truth Maintenance System, Agenda and Agenda Event Support.
- Object assertion may result in the creation of one or more Activations.
- The Agenda is responsible for scheduling the execution of these Activations.</para>
+ Packages. Packages can be added and removed from the RuleBase at any time.
+ A RuleBase can instantiate one or more WorkingMemories at any time; a weak
+ reference is maintained, unless configured otherwise. The Working Memory
+ consists of a number of sub components, inculding Working Memory Event
+ Support, Truth Maintenance System, Agenda and Agenda Event Support. Object
+ assertion may result in the creation of one or more Activations. The
+ Agenda is responsible for scheduling the execution of these
+ Activations.</para>
<figure>
<title>Runtime Components</title>
@@ -72,26 +73,26 @@
</mediaobject>
</figure>
- <para>Three classes are used for authoring: DrlParser, XmlParser and
- PackageBuilder. The two parser classes produce "descr" AST models from a
+ <para>Three classes are used for authoring: DrlParser, XmlParser and
+ PackageBuilder. The two parser classes produce "descr" AST models from a
provided Reader instance. PackageBuilder provides convienience APIs so
that you can mostly forget about those classes. The two convienience
methods are "addPackageFromDrl" and "addPackageFromXml" - both take an
instance of Reader as an argument. The example below shows how to build a
- package that includes both XML and DRL rule files, which are in
- the classpath. Note that all added package sources must be of the same
- package namespace for the current PackageBuilder instance!</para>
+ package that includes both XML and DRL rule files, which are in the
+ classpath. Note that all added package sources must be of the same package
+ namespace for the current PackageBuilder instance!</para>
<example>
<title>Building a Package from Multiple Sources</title>
<programlisting>
- <![CDATA[
+
PackageBuilder builder = new PackageBuilder();
builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "package1.drl" ) ) );
builder.addPackageFromXml( new InputStreamReader( getClass().getResourceAsStream( "package2.drl" ) ) );
Package pkg = builder.getPackage();
- ]]>
+
</programlisting>
</example>
@@ -110,11 +111,11 @@
<title>Configuring the PackageBuilder to use JANINO</title>
<programlisting>
- <![CDATA[
+
PackageBuilderConfiguration conf = new PackageBuilderConfiguration();
conf.setCompiler( PackageBuilderConfiguration.JANINO );
PackageBuilder builder = new PackageBuilder( conf );
- ]]>
+
</programlisting>
</example>
@@ -126,11 +127,11 @@
compatability</title>
<programlisting>
- <![CDATA[
+
PackageBuilderConfiguration conf = new PackageBuilderConfiguration();
conf.setJavaLanguageLevel( "1.5" );
PackageBuilder builder = new PackageBuilder( conf );
- ]]>
+
</programlisting>
</example>
@@ -183,10 +184,10 @@
namespace may be added.</para>
<programlisting>
- <![CDATA[
+
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage( pkg );
- ]]>
+
</programlisting>
<figure>
@@ -204,22 +205,22 @@
</figure>
<para>A Rule Base instance is threadsafe, in the sense that you can have
- the one instance shared across threads in your application, which may be
- a web application, for instance. The most common operation on a rulebase
- is to create a new WorkingMemory.</para>
+ the one instance shared across threads in your application, which may be a
+ web application, for instance. The most common operation on a rulebase is
+ to create a new WorkingMemory.</para>
<para>The Rule Base also holds weak references to any working memories
- that it has spawned, so that if rules are changing (or being added/removed etc.
- for long running working memories), they can be updated with the latest
- rules (without necessarily having to restart the working memory). You can
- specify not to maintain a weak reference, but only do so if you know the
- Rule Base will not be updated.</para>
+ that it has spawned, so that if rules are changing (or being added/removed
+ etc. for long running working memories), they can be updated with the
+ latest rules (without necessarily having to restart the working memory).
+ You can specify not to maintain a weak reference, but only do so if you
+ know the Rule Base will not be updated.</para>
<programlisting>
- <![CDATA[
+
ruleBase.newWorkingMemory(); // maintains a weak reference.
ruleBase.newWorkingMemory( false ); // do not maintain a weak reference
- ]]>
+
</programlisting>
<para>Packages can be added and removed at any time - all changes will be
@@ -227,11 +228,11 @@
fireAllRules() for resulting Activations to fire.</para>
<programlisting>
- <![CDATA[
+
ruleBase.addPackage( pkg ); // Add a package instance
ruleBase.removePackage( "org.com.sample" ); // remove a package, and all its parts, by it's namespace
ruleBase.removeRule( "org.com.sample", "my rule" ); // remove a specific rule from a namespace
- ]]>
+
</programlisting>
<para>While there is a method to remove an indivual rule, there is no
@@ -243,20 +244,20 @@
added to a Rule Base.</para>
<programlisting>
- <![CDATA[
+
RuleBaseConfiguration conf = new RuleBaseConfiguration();
conf.setProperty( RuleBaseConfiguration.PROPERTY_ASSERT_BEHAVIOR,
RuleBaseConfiguration..WM_BEHAVIOR_EQUALITY );
RuleBase ruleBase = new ReteooRuleBase( conf );
- ]]>
+
</programlisting>
- <para>The two main properties to be aware of are PROPERT_ASSERT_BEHAVIOR and
- PROPERTY_LOGICAL_OVERRIDE_BEHAVIOR, which are explain more in later sections.
- All properties and their values are public static field constants on
- RuleBaseConfiguration.</para>
+ <para>The two main properties to be aware of are PROPERT_ASSERT_BEHAVIOR
+ and PROPERTY_LOGICAL_OVERRIDE_BEHAVIOR, which are explain more in later
+ sections. All properties and their values are public static field
+ constants on RuleBaseConfiguration.</para>
<figure>
<title>RuleBaseConfiguration</title>
@@ -303,10 +304,10 @@
alternative pattern is a working memory that is kept around for a longer
time (such as a conversation) - and kept updated with new facts. When you
wish to dispose of WorkingMemory the best pactice is to use the dispose()
- method, so that the reference to it is removed in the parent Rule Base. However,
- this is a weak reference, so it should eventually be garbage collected
- anyway. The term Working Memory Action is used to describe assertions,
- retractions and modifications with the Working Memory.</para>
+ method, so that the reference to it is removed in the parent Rule Base.
+ However, this is a weak reference, so it should eventually be garbage
+ collected anyway. The term Working Memory Action is used to describe
+ assertions, retractions and modifications with the Working Memory.</para>
<section>
<title>Facts</title>
@@ -328,24 +329,26 @@
facts. WorkingMemory.assertObject(yourObject) for example. When you
assert a fact, it is examined for matches against the rules etc. This
means ALL of the work is done during assertion; however, no rules are
- executed until you call "fireAllRules()". You don't call "fireAllRules()"
- until after you have finished asserting
- your facts. This is a common misunderstanding by people who think the
- work happens when you call "fireAllRules()".</para>
+ executed until you call "fireAllRules()". You don't call
+ "fireAllRules()" until after you have finished asserting your facts.
+ This is a common misunderstanding by people who think the work happens
+ when you call "fireAllRules()".</para>
+
<!-- FIXME - I think we might want to add this sentence to the previous paragraph.
However, when the rules are executed, they can assert new objects
thus causing new work to be needed.
-->
+
<para>When an Object is asserted it returns a FactHandle. This
FactHandle is the token used to represent your asserted Object inside
the WorkingMemory, it is also how you will interact with the Working
Memory when you wish to retract or modify an object.</para>
<programlisting>
- <![CDATA[
+
Cheese stilton = new Cheese("stilton");
FactHandle stiltonHandle = workingMemory.assertObject( stilton );
- ]]>
+
</programlisting>
<para>As mentioned in the Rule Base section a Working Memory may operate
@@ -375,12 +378,12 @@
FactHandle that was returned during the assert.</para>
<programlisting>
- <![CDATA[
+
Cheese stilton = new Cheese("stilton");
FactHandle stiltonHandle = workingMemory.assertObject( stilton );
....
workingMemory.retractObject( stiltonHandle );
- ]]>
+
</programlisting>
</section>
@@ -397,13 +400,13 @@
objects.</para>
<programlisting>
- <![CDATA[
+
Cheese stilton = new Cheese("stilton");
FactHandle stiltonHandle = workingMemory.assertObject( stilton );
....
stilton.setPrice( 100 );
workingMemory.modifyObject( stiltonHandle, stilton );
- ]]>
+
</programlisting>
</section>
@@ -419,10 +422,10 @@
dynamic mode specify true for the second assertObject parameter.</para>
<programlisting>
- <![CDATA[
+
Cheese stilton = new Cheese("stilton");
FactHandle stiltonHandle = workingMemory.assertObject( stilton, true ); //specifies that this is a dynamic fact
- ]]>
+
</programlisting>
<para>To make a JavaBean dynamic add a PropertyChangeSupport field
@@ -430,7 +433,7 @@
notifies the PropertyChangeSupport instance of the change.</para>
<programlisting>
- <![CDATA[
+
private final PropertyChangeSupport changes = new PropertyChangeSupport( this );
...
public void addPropertyChangeListener(final PropertyChangeListener l) {
@@ -449,7 +452,7 @@
oldState,
newState );
}
- ]]>
+
</programlisting>
</section>
@@ -462,10 +465,10 @@
perhaps a means to return objects from the rule engine.</para>
<programlisting>
- <![CDATA[
+
new List list = new ArrayList;
workingMemory.setGlobal("list", list);
- ]]>
+
</programlisting>
<para>The global definition must be defined in the Rule Base and of the
@@ -508,21 +511,21 @@
</section>
<section>
- <title>Initial Fact</title>
- <para>
- To support conditional elements like "not" (which will be covered later on), there
- is a need to "seed" the engine with something known as the "Initial Fact". This fact
- is a special fact that is not intended to be seen by the user.</para>
-
- <para>
- On the first working memory action (assert, fireAllRules) on a fresh working memory,
- the Initial Fact will be propagated through the RETE network. This allows rules that
- have no LHS, or perhaps do not use normal facts (such as rules that use "from"
- to pull data from an external source). For instance, if a new working memory is created,
- and no facts are asserted, calling the fireAllRules will cause the Initial Fact to
- propagate, possibly activating rules (otherwise, nothing would happen as there area
- no other facts to start with).
- </para>
+ <title>Initial Fact</title>
+
+ <para>To support conditional elements like "not" (which will be covered
+ later on), there is a need to "seed" the engine with something known as
+ the "Initial Fact". This fact is a special fact that is not intended to
+ be seen by the user.</para>
+
+ <para>On the first working memory action (assert, fireAllRules) on a
+ fresh working memory, the Initial Fact will be propagated through the
+ RETE network. This allows rules that have no LHS, or perhaps do not use
+ normal facts (such as rules that use "from" to pull data from an
+ external source). For instance, if a new working memory is created, and
+ no facts are asserted, calling the fireAllRules will cause the Initial
+ Fact to propagate, possibly activating rules (otherwise, nothing would
+ happen as there area no other facts to start with).</para>
</section>
<section>
@@ -577,15 +580,15 @@
<para>Working Memory Actions - this is where most of the work takes
place - in either the Consequence or the main java application
process. Once the Consequence has finished or the main Java
- application process calls fireAllRules() the engine switches to the Agenda
- Evaluation phase.</para>
+ application process calls fireAllRules() the engine switches to the
+ Agenda Evaluation phase.</para>
</listitem>
<listitem>
<para>Agenda Evaluation - attempts to select a rule to fire, if a rule
- is not found it exits, otherwise it attempts to fire the found rule, switching
- the phase back to Working Memory Actions and the process repeats again
- until the Agenda is empty.</para>
+ is not found it exits, otherwise it attempts to fire the found rule,
+ switching the phase back to Working Memory Actions and the process
+ repeats again until the Agenda is empty.</para>
</listitem>
</orderedlist>
@@ -654,8 +657,6 @@
on the stack. The default Agenda Group is "MAIN", all rules which do not
specify an Agenda Group are placed there, it is also always the first
group on the Stack and given focus as default.</para>
-
-
</section>
<section>
@@ -699,19 +700,17 @@
"Test":</para>
<programlisting>
- <![CDATA[
+
workingMemory.fireAllRules( new RuleNameEndsWithAgendaFilter( "Test" ) );
- ]]>
+
</programlisting>
</section>
</section>
<section>
- <title>Truth Maintenance with
- <indexterm>
+ <title>Truth Maintenance with <indexterm>
<primary>Logical Object</primary>
- </indexterm>
- Logical Objects</title>
+ </indexterm> Logical Objects</title>
<para>In a regular assertion, you need to explicitly retract a fact. With
logical assertions, the fact that was asserted will be automatically
@@ -724,8 +723,8 @@
stated - just like the intuitive concept). Using a HashMap and a counter
we track how many times a particuar equality is STATED; this means we
count how many different instances are equal. When we logically assert an
- object we are said to justify it and it is justified by the firing
- rule. For each logical assertion there can only be one equal object, each
+ object we are said to justify it and it is justified by the firing rule.
+ For each logical assertion there can only be one equal object, each
subsequent equal logical assertion increases the justification counter for
this logical assertion. As each justification is removed when we have no
more justifications the logical object is automatically retracted.</para>
@@ -739,9 +738,9 @@
this is the default behaviour - otherwise we overrde it to STATED but we
create an new FactHandle.</para>
- <para>This can be confusing on a first read, so hopefully the flow
- charts below help. When it says that it returns a new FactHandle, this
- also indicates the Object was propagated through the network.</para>
+ <para>This can be confusing on a first read, so hopefully the flow charts
+ below help. When it says that it returns a new FactHandle, this also
+ indicates the Object was propagated through the network.</para>
<figure>
<title>Stated Assertion</title>
@@ -775,43 +774,57 @@
</mediaobject>
</figure>
- <section>
- <title>Example Scenario</title>
+ <section>
+ <title>Example Scenario</title>
- <para>An example may make things clearer. Imagine a credit card
- processing application, processing transactions for a given account
- (and we have a working memory accumulating knowledge about a single
- accounts transaction). The rule engine is doing its best to decide if
- transactions are possibly fraudulent or not. Imagine this rule base
- basically has rules that kick in when there is "reason to be
- suspicious" and when "everything is normal".</para>
+ <para>An example may make things clearer. Imagine a credit card
+ processing application, processing transactions for a given account (and
+ we have a working memory accumulating knowledge about a single accounts
+ transaction). The rule engine is doing its best to decide if
+ transactions are possibly fraudulent or not. Imagine this rule base
+ basically has rules that kick in when there is "reason to be suspicious"
+ and when "everything is normal".</para>
- <para>Of course there are many rules that operate no matter what
- (performing standard calculations, etc.). Now there are possibly many
- reasons as to what could trigger a "reason to be suspicious": someone
- notifying the bank, a sequence of large transactions, transactions for
- geographically disparate locations or even reports of credit card
- theft. Rather then smattering all the little conditions in lots of
- rules, imagine there is a fact class called
- "SuspiciousAccount".</para>
+ <para>Of course there are many rules that operate no matter what
+ (performing standard calculations, etc.). Now there are possibly many
+ reasons as to what could trigger a "reason to be suspicious": someone
+ notifying the bank, a sequence of large transactions, transactions for
+ geographically disparate locations or even reports of credit card theft.
+ Rather then smattering all the little conditions in lots of rules,
+ imagine there is a fact class called "SuspiciousAccount".</para>
- <para>Then there can be a series of rules whose job is to look for
- things that may raise suspicion, and if they fire, they simply assert
- a new SuspiciousAccount() instance. All the other rules just have
- conditions like "not SuspiciousAccount()" or "SuspiciousAccount()"
- depending on their needs. Note that this has the advantage of allowing
- there to be many rules around raising suspicion, without touching the
- other rules. When the facts causing the SuspiciousAccount() assertion
- are removed, the rule engine reverts back to the normal "mode" of
- operation (and for instance, a rule with "not SuspiciousAccount()" may
- kick in which flushes through any interrupted transactions).</para>
+ <para>Then there can be a series of rules whose job is to look for
+ things that may raise suspicion, and if they fire, they simply assert a
+ new SuspiciousAccount() instance. All the other rules just have
+ conditions like "not SuspiciousAccount()" or "SuspiciousAccount()"
+ depending on their needs. Note that this has the advantage of allowing
+ there to be many rules around raising suspicion, without touching the
+ other rules. When the facts causing the SuspiciousAccount() assertion
+ are removed, the rule engine reverts back to the normal "mode" of
+ operation (and for instance, a rule with "not SuspiciousAccount()" may
+ kick in which flushes through any interrupted transactions).</para>
- <para>If you have followed this far, you will note that truth
- maintenance, like logical assertions, allows rules to behave a little
- like a human would, and can certainly make the rules more
- managable.</para>
- </section>
+ <para>If you have followed this far, you will note that truth
+ maintenance, like logical assertions, allows rules to behave a little
+ like a human would, and can certainly make the rules more
+ managable.</para>
+ </section>
+ <section>
+ <title>Important note: Equality for Java objects</title>
+
+ <para>It is important to note that for Truth Maintenance (and logical
+ assertions) to work at all, your Fact objects (which may be Javabeans)
+ override equals and hashCode methods (from java.lang.Object) correctly.
+ As the truth maintnance system needs to know when 2 different physical
+ objects are equal in value, BOTH equals and hashCode must be overridden
+ correctly, as per the Java standard.</para>
+
+ <para>Two objects are equal if and only if their equals methods return
+ true for each other and if their hashCode methods return the same
+ values. See the Java API for more details (but do keep in mind you MUST
+ override both equals and hashCode).</para>
+ </section>
</section>
<section>
@@ -867,14 +880,14 @@
fired:</para>
<programlisting>
- <![CDATA[
+
workingMemory.addEventListener( new DefaultAgendaEventListener() {
public void afterActivationFired(AfterActivationFiredEvent event) {
super.afterActivationFired( event );
System.out.println( event );
}
});
- ]]>
+
</programlisting>
<para>Drools also provides DebugWorkingMemoryEventListener and
@@ -882,9 +895,9 @@
statement:</para>
<programlisting>
- <![CDATA[
+
workingMemory.addEventListener( new DebugWorkingMemoryEventListener() );
- ]]>
+
</programlisting>
<para>The Eclipse based Rule IDE also provides an audit logger and
More information about the jboss-svn-commits
mailing list