[jboss-svn-commits] JBL Code SVN: r25862 - labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Fri Mar 27 23:19:22 EDT 2009
Author: mark.proctor at jboss.com
Date: 2009-03-27 23:19:22 -0400 (Fri, 27 Mar 2009)
New Revision: 25862
Modified:
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.xml
Log:
more updates to quick start
Modified: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.xml 2009-03-27 17:30:21 UTC (rev 25861)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.xml 2009-03-28 03:19:22 UTC (rev 25862)
@@ -1,49 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
-<chapter version="5.0" xmlns="http://docbook.org/ns/docbook"
- xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:svg="http://www.w3.org/2000/svg" xmlns:m="http://www.w3.org/1998/Math/MathML"
- xmlns:html="http://www.w3.org/1999/xhtml" xml:base="./">
+<chapter version="5.0" xml:base="./" xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:ns="http://docbook.org/ns/docbook"
+ xmlns:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml">
<title>Quick Start</title>
+
<section>
<title>The Basics</title>
+
<section>
<title>Stateless Knowledge Session</title>
- <para>So where do we get started, there are so many use cases and so much functionality in a
- rule engine such as Drools that it becomes beguiling. Have no fear my intrepid adventurer,
- the complexity is layered and you can ease yourself into with simple use cases.</para>
- <para>Stateless session, not utilising inference, forms the simplest of use case. A stateless
- session can be called like a function passing it some data and then receiving some results
- back. Some common use cases for stateless sessions are, but not limited to:</para>
+
+ <para>So where do we get started, there are so many use cases and so
+ much functionality in a rule engine such as Drools that it becomes
+ beguiling. Have no fear my intrepid adventurer, the complexity is
+ layered and you can ease yourself into with simple use cases.</para>
+
+ <para>Stateless session, not utilising inference, forms the simplest of
+ use case. A stateless session can be called like a function passing it
+ some data and then receiving some results back. Some common use cases
+ for stateless sessions are, but not limited to:</para>
+
<itemizedlist>
<listitem>
<para>Validation</para>
+
<itemizedlist>
<listitem>
<para>Is this person legible for a mortgage</para>
</listitem>
</itemizedlist>
</listitem>
+
<listitem>
<para>Calculation</para>
+
<itemizedlist>
<listitem>
<para>Mortgage premium</para>
</listitem>
</itemizedlist>
</listitem>
+
<listitem>
<para>Routing/Filtering</para>
+
<itemizedlist>
<listitem>
- <para>Filtering incoming messages, such as emails, into folders</para>
+ <para>Filtering incoming messages, such as emails, into
+ folders</para>
</listitem>
+
<listitem>
<para>Sending incoming message to a destinatino</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
- <para>So lets start with a very simple example using a driving license application.</para>
+
+ <para>So lets start with a very simple example using a driving license
+ application.</para>
+
<programlisting>public class Applicant {
private String name;
private int age;
@@ -51,10 +71,13 @@
// getter and setter methods here
}
</programlisting>
- <para>Now we have our data model we can write our first rule, we assume the application starts
- off valid and rules would be used to disqualify the application. As this is a simple
- validation use case we will add a single rule to disqualify the applicant if they are
- younger than 18.</para>
+
+ <para>Now we have our data model we can write our first rule, we assume
+ the application starts off valid and rules would be used to disqualify
+ the application. As this is a simple validation use case we will add a
+ single rule to disqualify the applicant if they are younger than
+ 18.</para>
+
<programlisting>package com.company.license
rule "Is of valid age"
@@ -63,43 +86,57 @@
then
$a.setValid( false );
end</programlisting>
- <para>To make the engine aware of data, so it can be processed against the rules, we have to
- "insert" the data, much like with a database. When the Applicant instance is inserted into
- the engine it is evaluated against the constraints of the rules, in this case just two
- constraint for one rule. We say two because the type Applicant is the first object type
- constraint, and the "age < 18" is the second field constraint. An object type constraint
- plus it's zero or more field constraints is referred to as a pattern. When an inserted
- instance satisfies both the object type constraint and all the field constraints, it is said
- to be matched. The "$a" is a binding and allows the matched object to be referenced in the
- consquence, so it's properties can be updated, the $ is optional, but it helps to
- differentiate the variables from the fields. This part of the engine is often referred to as
- pattern matchin, i.e. the matching of patterns against the inserted data.</para>
- <para>Let's assume that the rules are in the same folder as the classes, so we can use the
- classpath resource loader to build our first KnowledgeBase. A KnowledgeBase is what we call
- our collection of compiled rules, which are compiled using the KnowledgeBuilder.</para>
+
+ <para>To make the engine aware of data, so it can be processed against
+ the rules, we have to "insert" the data, much like with a database. When
+ the Applicant instance is inserted into the engine it is evaluated
+ against the constraints of the rules, in this case just two constraint
+ for one rule. We say two because the type Applicant is the first object
+ type constraint, and the "age < 18" is the second field constraint.
+ An object type constraint plus it's zero or more field constraints is
+ referred to as a pattern. When an inserted instance satisfies both the
+ object type constraint and all the field constraints, it is said to be
+ matched. The "$a" is a binding and allows the matched object to be
+ referenced in the consquence, so it's properties can be updated, the $
+ is optional, but it helps to differentiate the variables from the
+ fields. This part of the engine is often referred to as pattern matchin,
+ i.e. the matching of patterns against the inserted data.</para>
+
+ <para>Let's assume that the rules are in the same folder as the classes,
+ so we can use the classpath resource loader to build our first
+ KnowledgeBase. A KnowledgeBase is what we call our collection of
+ compiled rules, which are compiled using the KnowledgeBuilder.</para>
+
<programlisting>KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newClasspathResource( "licenseApplication.drl", getClass() ),
ResourceType.DRL );
if ( kbuilder.hasErrors() ) {
System.err.println( builder.getErrors().toString() );
} </programlisting>
- <para>The above looks on the classpath for the "licenseApplication.drl" file, using the given
- classes getResource() method. The ResourceType here is DRL, short for "Drools Rule
- Language". Once the drl has be added we can check the KnowledgeBuilder for any errors. If
- there are no errors, we are now ready to build our session and execute against some
- data:</para>
+
+ <para>The above looks on the classpath for the "licenseApplication.drl"
+ file, using the given classes getResource() method. The ResourceType
+ here is DRL, short for "Drools Rule Language". Once the drl has be added
+ we can check the KnowledgeBuilder for any errors. If there are no
+ errors, we are now ready to build our session and execute against some
+ data:</para>
+
<programlisting>StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
Applicant applicant = new Applicant( "Mr John Smith", 16 );
assertTrue( applicant.isValid() );
ksession.execute( applicant );
assertFalse( applicant.isValid() );
</programlisting>
- <para>The above executes the data against the rules, the applicant is under the age of 18, so
- it marked invalid.</para>
- <para>So far we've only used a single instance, but what if want to use more than one? We can
- also execute against an Iterable, such a a collection. Lets add another class called
- Application, which has the date of the application and we'll move the boolean valid field to
- the Application class.</para>
+
+ <para>The above executes the data against the rules, the applicant is
+ under the age of 18, so it marked invalid.</para>
+
+ <para>So far we've only used a single instance, but what if want to use
+ more than one? We can also execute against an Iterable, such a a
+ collection. Lets add another class called Application, which has the
+ date of the application and we'll move the boolean valid field to the
+ Application class.</para>
+
<programlisting>public class Applicant {
private String name;
private int age;
@@ -112,8 +149,10 @@
private boolean valid;
// getter and setter methods here
}</programlisting>
- <para>And we can also add another rule, that validates the Application was made within a
- period of time.</para>
+
+ <para>And we can also add another rule, that validates the Application
+ was made within a period of time.</para>
+
<programlisting>package com.company.license
rule "Is of valid age"
@@ -131,9 +170,12 @@
$a.setValid( false );
end
</programlisting>
- <para>Unfortunately in java an array does not implement h the Iterable interface, so we have
- to use the JDK converter, asList(...). So code below executes against an Iterable, where
- each of the collection elements are inserted before any matched rules are fired.</para>
+
+ <para>Unfortunately in java an array does not implement h the Iterable
+ interface, so we have to use the JDK converter, asList(...). So code
+ below executes against an Iterable, where each of the collection
+ elements are inserted before any matched rules are fired.</para>
+
<programlisting>StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
Applicant applicant = new Applicant( "Mr John Smith", 16 );
Application application = new Application();
@@ -141,42 +183,74 @@
ksession.execute( Arrays.asList( new Object[] { application, applicant } ) );
assertFalse( application() );
</programlisting>
- <para>The two execute methods execute(Object object ) and execute(Iterable objects) are
- actually convenience methods for the interface BatchExecutor's method execute(Command
- command). This allows for more than just fact insertion, and also handles "out" parameters
- and results.</para>
+
+ <para>The two execute methods execute(Object object ) and
+ execute(Iterable objects) are actually convenience methods for the
+ interface BatchExecutor's method execute(Command command).</para>
+
+ <para>The CommandFactory is used to return commands, the following is
+ equivalent of execute( Iterable it ):</para>
+
+ <programlisting>ksession.execute( CommandFactory.newInsertIterable( new Object[] { application, applicant } ) );
+</programlisting>
+
+ <para>Where the the BatchExecutor and CommandFactory becomes useful is
+ while working with multiple Commands and out identifiers for
+ results.</para>
+
+ <programlisting>List<Command> cmds = new ArrayList<Command>();
+cmds.add( CommandFactory.newInsert( new Person( "Mr John Smith" ), "mrSmith" );
+cmds.add( CommandFactory.newInsert( new Person( "Mr John Doe" ), "mrDoe" );
+BatchExecutionResults results = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
+assertEquals( new Person( "Mr John Smith" ), results.getValue( "mrSmith" ) );
+</programlisting>
+
+ <para>CommandFactory supports many other Commands that can be used in
+ the BatchExecutor like StartProcess, Query, SetGlobal.</para>
</section>
+
<section>
<title>Stateful Knowledge Session</title>
- <para>Stateful sessions are longer lived and allow iterative changes over time. Some common
- use cases for stateful sessions are, but not limited to:</para>
+
+ <para>Stateful sessions are longer lived and allow iterative changes
+ over time. Some common use cases for stateful sessions are, but not
+ limited to:</para>
+
<itemizedlist>
<listitem>
<para>Monitoring</para>
+
<itemizedlist>
<listitem>
- <para>Stock market monitorig and analysis for semi-automatic buying.</para>
+ <para>Stock market monitorig and analysis for semi-automatic
+ buying.</para>
</listitem>
</itemizedlist>
</listitem>
+
<listitem>
<para>Diagnostics</para>
+
<itemizedlist>
<listitem>
<para>fault finding, medical diagnostics</para>
</listitem>
</itemizedlist>
</listitem>
+
<listitem>
<para>Logistics</para>
+
<itemizedlist>
<listitem>
<para>parcel tracking and delivery provisioning</para>
</listitem>
</itemizedlist>
</listitem>
+
<listitem>
<para>Compliance</para>
+
<itemizedlist>
<listitem>
<para>Validation of legality for market trades.</para>
@@ -184,9 +258,20 @@
</itemizedlist>
</listitem>
</itemizedlist>
- <para>We can use a fire alarm example to explore the monitoring use case. The simple example
- has just 4 classes. We are monitoring the rooms in a house, each room has one sprinkler. If
- a fire starts in a room, we represent that with a single Fire instance.</para>
+
+ <para>Unlike a stateless session the dispose() method must be called
+ afterwards to ensure there are no memory leaks, as the KnowledgeBase
+ contained references to StatefulKnowledgeSessions when they are created.
+ StatefulKnowledgeSession also supports the BatchExecutor interface like
+ StatelessKnowledgeSession, the only difference is that when used with
+ stateful the FireAllRules command is not automatically called at the
+ end.</para>
+
+ <para>We can use a fire alarm example to explore the monitoring use
+ case. The simple example has just 4 classes. We are monitoring the rooms
+ in a house, each room has one sprinkler. If a fire starts in a room, we
+ represent that with a single Fire instance.</para>
+
<programlisting>public class Room {
private String name
// getter and setter methods here
@@ -203,16 +288,22 @@
public class Alarm {
}
</programlisting>
- <para>In the previous section on stateless sessions the concepts of inserting and matching
- against data was introduced. That example assumed only a single instance of each object type
- was ever inserted and thus only used literal constraints. However a house has many rooms, so
- rules have the need to express joins that constraint to the desired objects, this can be
- done using a binding as a variable constraint in a pattern. This join process results in
- what is called cross products, which are covered in the next section.</para>
- <para>When a fire occurs an instance of the Fire class is created, for that room, and insert
- it. The rule uses a binding on the room field of the Fire to constrain to the Sprinkler for
- that room, which is currently off. When this rule fires and the consequence is executed the
- sprinkler is turned on</para>
+
+ <para>In the previous section on stateless sessions the concepts of
+ inserting and matching against data was introduced. That example assumed
+ only a single instance of each object type was ever inserted and thus
+ only used literal constraints. However a house has many rooms, so rules
+ have the need to express joins that constraint to the desired objects,
+ this can be done using a binding as a variable constraint in a pattern.
+ This join process results in what is called cross products, which are
+ covered in the next section.</para>
+
+ <para>When a fire occurs an instance of the Fire class is created, for
+ that room, and insert it. The rule uses a binding on the room field of
+ the Fire to constrain to the Sprinkler for that room, which is currently
+ off. When this rule fires and the consequence is executed the sprinkler
+ is turned on</para>
+
<programlisting>rule "When there is a fire turn on the sprinkler"
when
Fire($room : room)
@@ -221,18 +312,25 @@
modify( $sprinkler ) { setOn( true ) };
System.out.println( "Turn off the sprinkler for room " + $room.getName() );
end</programlisting>
- <para>Where as the stateless session used standard java syntax to modify a field, in the above
- rule we use the modify keyword, which acts as a sort of with statement, that contains a
- series of comma separated java expressions. Stateless sessions do not have inference, so the
- engine does not need to be aware of changes to data, however a stateful session does. The
- modify keyword allows the setters to modify the data, while make the engine aware of those
- changes so it can reason over them, this process is called inference.</para>
- <para>So far we have rules that tell us when matching data exists, but what about when it
- doesn't exist? What about when there stops being a Fire? Previously the constraints have
- been propositional logic where the engine is constraining against individual intances,
- Drools also has support for first order logic that allows you to look at sets of data. The
- 'not' keyword matches when something does not exist. So for a Room with a Sprinkler that is
- on when the Fire for that room stops existing we can turn off the sprinkler.</para>
+
+ <para>Where as the stateless session used standard java syntax to modify
+ a field, in the above rule we use the modify keyword, which acts as a
+ sort of with statement, that contains a series of comma separated java
+ expressions. Stateless sessions do not have inference, so the engine
+ does not need to be aware of changes to data, however a stateful session
+ does. The modify keyword allows the setters to modify the data, while
+ make the engine aware of those changes so it can reason over them, this
+ process is called inference.</para>
+
+ <para>So far we have rules that tell us when matching data exists, but
+ what about when it doesn't exist? What about when there stops being a
+ Fire? Previously the constraints have been propositional logic where the
+ engine is constraining against individual intances, Drools also has
+ support for first order logic that allows you to look at sets of data.
+ The 'not' keyword matches when something does not exist. So for a Room
+ with a Sprinkler that is on when the Fire for that room stops existing
+ we can turn off the sprinkler.</para>
+
<programlisting>rule "When the fire is gone turn on the sprinkler"
when
$room : Room( )
@@ -242,10 +340,13 @@
modify( $sprinkler ) { setOn( false ) };
System.out.println( "Turn off the sprinkler for room " + $room.getName() );
end</programlisting>
- <para>While there is a Sprinkler per room, there is just a single Alarm for the building. An
- Alarm is created when a Fire is occurs, but only one Alarm is needed for the entire
- building, no matter how many Fires occur. Previously 'not' was introduced, the compliment to
- ths is 'exists' which matches for one or more of something.</para>
+
+ <para>While there is a Sprinkler per room, there is just a single Alarm
+ for the building. An Alarm is created when a Fire is occurs, but only
+ one Alarm is needed for the entire building, no matter how many Fires
+ occur. Previously 'not' was introduced, the compliment to ths is
+ 'exists' which matches for one or more of something.</para>
+
<programlisting>rule "Raise the alarm when we have one or more fires"
when
exists Fire()
@@ -253,8 +354,10 @@
insert( new Alarm() );
System.out.println( "Raise the alarm" );
end</programlisting>
- <para>Likewise when there are no Fires we want to remove the alarm, so the 'not' keyword can
- be used again.</para>
+
+ <para>Likewise when there are no Fires we want to remove the alarm, so
+ the 'not' keyword can be used again.</para>
+
<programlisting>rule "Lower the alarm when all the fires have gone"
when
not Fire()
@@ -265,8 +368,11 @@
end
</programlisting>
- <para>Finally there is a general health status message, that is printed when the application
- first starts and after the Alarm is removed and all Sprinklers have been turned off.</para>
+
+ <para>Finally there is a general health status message, that is printed
+ when the application first starts and after the Alarm is removed and all
+ Sprinklers have been turned off.</para>
+
<programlisting>rule "Status output when things are ok"
when
not Alarm()
@@ -274,11 +380,14 @@
then
System.out.println( "Everything is ok" );
end</programlisting>
- <para>The above rules should be placed in a single drl file and saved to the classpath using
- the file name "fireAlarm.drl", as per the stateless session example. We can then build a
- KnowledgeBase as before, just using the new name "fireAlarm.drl". The difference is this
- time we create a stateful session from the kbase, where as before we created a stateless
- session.</para>
+
+ <para>The above rules should be placed in a single drl file and saved to
+ the classpath using the file name "fireAlarm.drl", as per the stateless
+ session example. We can then build a KnowledgeBase as before, just using
+ the new name "fireAlarm.drl". The difference is this time we create a
+ stateful session from the kbase, where as before we created a stateless
+ session.</para>
+
<programlisting>KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newClasspathResource( "fireAlarm.drl", getClass() ),
ResourceType.DRL );
@@ -286,11 +395,14 @@
System.err.println( builder.getErrors().toString() );
}
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();</programlisting>
- <para>With the session created it is now possible to iteratvely work with it over time. Four
- Rooms are created and inserted, a Sprinkler for each room is also inserted. At this point
- the engine has done all it's matching, but no rules have fired. calling "fireAllRules" on
- the ksession allows the matched rules to fire, currently that is just the health
- message.</para>
+
+ <para>With the session created it is now possible to iteratvely work
+ with it over time. Four Rooms are created and inserted, a Sprinkler for
+ each room is also inserted. At this point the engine has done all it's
+ matching, but no rules have fired. calling "fireAllRules" on the
+ ksession allows the matched rules to fire, currently that is just the
+ health message.</para>
+
<programlisting>Room kitchen = new Room( "kitchen" );
Room bedroom = new Room( "bedroom" );
Room office = new Room( "office" );
@@ -314,12 +426,16 @@
ksession.fireAllRules()
</programlisting>
+
<programlisting>> Everything is ok</programlisting>
- <para>We now create two fires and insert them, this time a referenced is kept for the returned
- FactHandle. The FactHandle is an internal engine reference to the inserted instance and
- allows that instance to be retracted or modified at a later point in time. With the Fires
- now in the engine, once "fireAllRules" is called, the Alarm is raised and the respectively
- Sprinklers are turned on.</para>
+
+ <para>We now create two fires and insert them, this time a referenced is
+ kept for the returned FactHandle. The FactHandle is an internal engine
+ reference to the inserted instance and allows that instance to be
+ retracted or modified at a later point in time. With the Fires now in
+ the engine, once "fireAllRules" is called, the Alarm is raised and the
+ respectively Sprinklers are turned on.</para>
+
<programlisting>Fire kitchenFire = new Fire( kitchen );
Fire officeFire = new Fire( office );
@@ -327,67 +443,88 @@
FactHandle officeFireHandle = ksession.insert( officeFire );
ksession.fireAllRules();</programlisting>
+
<programlisting>> Raise the alarm
> Turn on the sprinkler for room kitchen
> Turn on the sprinkler for room office</programlisting>
- <para>After a while the fires will be put out and the Fire intances are retracted. This
- results in the Sprinklers being turned off, the Alarm being lowered and eventually the
- health message is printed again.</para>
+
+ <para>After a while the fires will be put out and the Fire intances are
+ retracted. This results in the Sprinklers being turned off, the Alarm
+ being lowered and eventually the health message is printed again.</para>
+
<programlisting>ksession.retract( kitchenFire );
ksession.retract( officeFire );
ksession.fireAllRules();</programlisting>
+
<programlisting>> Turn on the sprinkler for room office
> Turn on the sprinkler for room kitchen
> Lower the alarm
> Everything is ok</programlisting>
- <para>Every one still with me? That wasn't so hard and already I'm hoping you can start to see
- the value and power of a declarative rule system.</para>
+
+ <para>Every one still with me? That wasn't so hard and already I'm
+ hoping you can start to see the value and power of a declarative rule
+ system.</para>
</section>
</section>
+
<section>
<title>A Little Theory</title>
+
<section>
<title>Methods versus Rules</title>
- <para>People often confuse methods and rules, and new rule users regular ask, "how do I call a
- rule?". After the last section, you are now feeling like a rule expert and the answer to
- that is obvsious, but just to summarise.</para>
+
+ <para>People often confuse methods and rules, and new rule users regular
+ ask, "how do I call a rule?". After the last section, you are now
+ feeling like a rule expert and the answer to that is obvsious, but just
+ to summarise.</para>
+
<programlisting>public void helloWorld(Person person) {
if ( person.getName().equals( “Chuck” ) ) {
System.out.println( “Hello Chuck” );
}
}</programlisting>
+
<itemizedlist>
<listitem>
<para>Methods are called directly.</para>
</listitem>
+
<listitem>
<para>Specific instances are passed.</para>
</listitem>
</itemizedlist>
+
<programlisting>rule “Hello World”
when
Person( name == “Chuck” )
then
System.out.println( “Hello Chuck” );
end</programlisting>
+
<itemizedlist>
<listitem>
- <para>Rules execute by matching against data inserted into the engine.</para>
+ <para>Rules execute by matching against data inserted into the
+ engine.</para>
</listitem>
+
<listitem>
<para>Rules can never be called directly.</para>
</listitem>
+
<listitem>
<para>Specific instances cannot be passed to a rule.</para>
</listitem>
</itemizedlist>
</section>
+
<section>
<title>Cross Products</title>
- <para>Earlier the term "cross product" was mentioned, which is the result of a join. Imagine
- for a moment when using the previous data the following rules where used, with no field
- constraints:</para>
+
+ <para>Earlier the term "cross product" was mentioned, which is the
+ result of a join. Imagine for a moment when using the previous data the
+ following rules where used, with no field constraints:</para>
+
<programlisting>rule
when
$room : Room()
@@ -395,9 +532,11 @@
then
System.out.println( "room:" + $room.getName() + " sprinkler:" + $sprinkler.getRoom().getName() );
end</programlisting>
- <para>In SQL terms this would be like doing "select * from Room, Sprinkler" and every row in
- the Room table would be joined with every row in the Sprinkler table resulting in the
- following output:</para>
+
+ <para>In SQL terms this would be like doing "select * from Room,
+ Sprinkler" and every row in the Room table would be joined with every
+ row in the Sprinkler table resulting in the following output:</para>
+
<programlisting>room:office sprinker:office
room:office sprinker:kitchen
room:office sprinker:livingroom
@@ -414,10 +553,13 @@
room:bedroom sprinker:kitchen
room:bedroom sprinker:livingroom
room:bedroom sprinker:bedroom</programlisting>
- <para>These cross products can obviously become huge as well as returning potentially
- incorrect data. The size of cross products is often source of performance problems for new
- rule authors. From this it can be seen that it's always desirable to constrain the cross
- products, which is done with the variable constriant.</para>
+
+ <para>These cross products can obviously become huge as well as
+ returning potentially incorrect data. The size of cross products is
+ often source of performance problems for new rule authors. From this it
+ can be seen that it's always desirable to constrain the cross products,
+ which is done with the variable constriant.</para>
+
<programlisting>rule
when
$room : Room()
@@ -425,17 +567,27 @@
then
System.out.println( "room:" + $room.getName() + " sprinkler:" + $sprinkler.getRoom().getName() );
end</programlisting>
- <para>Resulting in just for rows of data, with the correct Sprinkler for the Room. In SQL
- (actually HQL) terms that is like "select * from Room, Sprinkler where Room ==
- Sprinkler.room"</para>
+
+ <para>Resulting in just for rows of data, with the correct Sprinkler for
+ the Room. In SQL (actually HQL) terms that is like "select * from Room,
+ Sprinkler where Room == Sprinkler.room"</para>
+
<programlisting>room:office sprinker:office
room:kitchen sprinker:kitchen
room:livingroom sprinker:livingroom
room:bedroom sprinker:bedroom</programlisting>
</section>
+
<section>
- <title>Execution Control</title>
- <para/>
+ <title>Activations, Agenda and Conflict Sets.</title>
+
+ <para>So far the data and matching process has been simple and small. To
+ mix things up a bit a new example will be explored that handles cashflow
+ calculations over date periods and the state of the engine will be
+ illustrateively shown at key stages to help get a better understanding
+ of what is actually going on under the hood. Three classes will be used,
+ as shown below.</para>
+
<programlisting>public class Cashflow {
private Date date;
private double amount;
@@ -455,69 +607,99 @@
private Dte end
// getter and setter methods here
}</programlisting>
- <para>By now you already know how to create KnowledgeBases and how to instantiate facts to
- populate the StatefulKnowledgeSession, so tables will be used to show the state of the
- inserted data, as it makes things clearer for illustration purposes. The tables below show a
- single fact was inserted for the Account and a series of debit's and credit's as Cashflows
- over two quarters for that Account were inserted.</para>
+
+ <para>By now you already know how to create KnowledgeBases and how to
+ instantiate facts to populate the StatefulKnowledgeSession, so tables
+ will be used to show the state of the inserted data, as it makes things
+ clearer for illustration purposes. The tables below show a single fact
+ was inserted for the Account and a series of debit's and credit's as
+ Cashflows over two quarters for that Account were inserted.</para>
+
<table border="0">
<tbody>
<tr>
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="2" align="left" valign="top">Account</th>
+ <th align="left" colspan="2" valign="top">Account</th>
</tr>
+
<tr align="center">
<th>accountNo</th>
+
<th>balance</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>1</td>
+
<td>0</td>
</tr>
</tbody>
</table>
</td>
+
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="4" align="left">Cashflow</th>
+ <th align="left" colspan="4">Cashflow</th>
</tr>
+
<tr align="center">
<th>date</th>
+
<th>amount</th>
+
<th>type</th>
+
<th>accountNo</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>12-jan-09</td>
+
<td>100</td>
+
<td>CREDIT</td>
+
<td>1</td>
</tr>
+
<tr>
<td>2-feb-09</td>
+
<td>200</td>
+
<td>DEBIT</td>
+
<td>1</td>
</tr>
+
<tr>
<td>18-may-09</td>
+
<td>50</td>
+
<td>CREDIT</td>
+
<td>1</td>
</tr>
+
<tr>
<td>09-mar-09</td>
+
<td>75</td>
+
<td>CREDIT</td>
+
<td>1</td>
</tr>
</tbody>
@@ -526,10 +708,13 @@
</tr>
</tbody>
</table>
- <para>Two rules can be used to determine the debit and credit for that quarter and update the
- Account balance. The two rules below constraint the Cashflows for an Account for a given
- time period. Notice the "&&" which use short cut syntax to avoid repeating the field
- name twice.</para>
+
+ <para>Two rules can be used to determine the debit and credit for that
+ quarter and update the Account balance. The two rules below constraint
+ the Cashflows for an Account for a given time period. Notice the
+ "&&" which use short cut syntax to avoid repeating the field
+ name twice.</para>
+
<informaltable frame="void">
<tbody>
<tr>
@@ -540,12 +725,13 @@
acc : Account( $accountNo : accountNo )
CashFlow( type == CREDIT,
accountNo == $accountNo,
- date >= ap.start && <= ap.end,
+ date >= ap.start && <= ap.end,
$ammount : ammount )
then
acc.balance += $amount;
end</programlisting>
</td>
+
<td align="left" valign="top">
<programlisting>rule “decrease balance for AccountPeriod Debits”
when
@@ -553,7 +739,7 @@
acc : Account( $accountNo : accountNo )
CashFlow( type == DEBIT,
accountNo == $accountNo,
- date >= ap.start && <= ap.end,
+ date >= ap.start && <= ap.end,
$ammount : ammount )
then
acc.balance -= $amount;
@@ -562,26 +748,33 @@
</tr>
</tbody>
</informaltable>
- <para>If the AccountPeriod is set to the first quarter we constraint the “increase balance for
- AccountPeriod Credits” to two rows of data and “decrease balance for AccountPeriod Debits”
- to one row of data.</para>
- <table border="0px">
+
+ <para>If the AccountPeriod is set to the first quarter we constraint the
+ “increase balance for AccountPeriod Credits” to two rows of data and
+ “decrease balance for AccountPeriod Debits” to one row of data.</para>
+
+ <table border="0">
<tbody>
<tr>
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="2" align="left">AccountPeriod</th>
+ <th align="left" colspan="2">AccountPeriod</th>
</tr>
+
<tr align="center">
<th>start</th>
+
<th>end</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>01-jan-09</td>
+
<td>31-mar-09</td>
</tr>
</tbody>
@@ -590,51 +783,70 @@
</tr>
</tbody>
</table>
- <table border="0px">
+
+ <table border="0">
<tbody>
<tr>
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="3" align="left">Cashflow</th>
+ <th align="left" colspan="3">Cashflow</th>
</tr>
+
<tr align="center">
<th>date</th>
+
<th>amount</th>
+
<th>type</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>12-jan-09</td>
+
<td>100</td>
+
<td>CREDIT</td>
</tr>
+
<tr>
<td>09-mar-09</td>
+
<td>75</td>
+
<td>CREDIT</td>
</tr>
</tbody>
</table>
</td>
+
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="3" align="left">Cashflow</th>
+ <th align="left" colspan="3">Cashflow</th>
</tr>
+
<tr align="center">
<th>date</th>
+
<th>amount</th>
+
<th>type</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>02-feb-09</td>
+
<td>200</td>
+
<td>DEBIT</td>
</tr>
</tbody>
@@ -643,35 +855,47 @@
</tr>
</tbody>
</table>
- <para>The two Cashflow tables above represent the matched data for the two rules, the data is
- matched during the insertion stage and as you found in the previous chapter does not fire
- straight away, until fireAllRules() is called. Intstead the rule plus it's matched data is
- placed on the Agenda and referred to as an Activation. The Agenda is a table of Activations
- that are able to fire and have their consequences executed, when fireAllRules() is called.
- Each of the Activations on the Agneda are executed in turn. Notice that the order of
- execution so far is considered arbitrary.</para>
- <table border="0px">
+
+ <para>The two Cashflow tables above represent the matched data for the
+ two rules, the data is matched during the insertion stage and as you
+ found in the previous chapter does not fire straight away, until
+ fireAllRules() is called. Intstead the rule plus it's matched data is
+ placed on the Agenda and referred to as an Activation. The Agenda is a
+ table of Activations that are able to fire and have their consequences
+ executed, when fireAllRules() is called. Each of the Activations on the
+ Agneda are executed in turn. Notice that the order of execution so far
+ is considered arbitrary.</para>
+
+ <table border="0">
<tbody>
<tr>
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="3" align="left">Agenda</th>
+ <th align="left" colspan="3">Agenda</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>1</td>
+
<td>increase balance</td>
+
<td rowspan="3">arbitrary</td>
</tr>
+
<tr>
<td>2</td>
+
<td>decrease balance</td>
</tr>
+
<tr>
<td>3</td>
+
<td>increase balance</td>
</tr>
</tbody>
@@ -680,24 +904,32 @@
</tr>
</tbody>
</table>
- <para>After each of the above activations are fired, the Account has a balance of -25.</para>
- <table border="0px">
+
+ <para>After each of the above activations are fired, the Account has a
+ balance of -25.</para>
+
+ <table border="0">
<tbody>
<tr>
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="2" align="left">Account</th>
+ <th align="left" colspan="2">Account</th>
</tr>
+
<tr align="center">
<th>accountNo</th>
+
<th>balance</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>1</td>
+
<td>-25</td>
</tr>
</tbody>
@@ -706,25 +938,33 @@
</tr>
</tbody>
</table>
- <para>If the AccountPeriod is updated to Q2, we have just a single matched row of data, and
- thus just a single Activation on the Agenda.</para>
- <table border="0px">
+
+ <para>If the AccountPeriod is updated to Q2, we have just a single
+ matched row of data, and thus just a single Activation on the
+ Agenda.</para>
+
+ <table border="0">
<tbody>
<tr>
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="2" align="left">AccountPeriod</th>
+ <th align="left" colspan="2">AccountPeriod</th>
</tr>
+
<tr align="center">
<th>start</th>
+
<th>end</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>01-apr-09</td>
+
<td>30-jun-09</td>
</tr>
</tbody>
@@ -733,47 +973,63 @@
</tr>
</tbody>
</table>
- <table border="0px">
+
+ <table border="0">
<tbody>
<tr>
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="3" align="left">Cashflow</th>
+ <th align="left" colspan="3">Cashflow</th>
</tr>
+
<tr align="center">
<th>date</th>
+
<th>amount</th>
+
<th>type</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>18-may-09</td>
+
<td>50</td>
+
<td>CREDIT</td>
</tr>
</tbody>
</table>
</td>
+
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="3" align="left">Cashflow</th>
+ <th align="left" colspan="3">Cashflow</th>
</tr>
+
<tr align="center">
<th>date</th>
+
<th>amount</th>
+
<th>type</th>
</tr>
</thead>
+
<tbody>
<tr>
- <td/>
- <td/>
- <td/>
+ <td />
+
+ <td />
+
+ <td />
</tr>
</tbody>
</table>
@@ -781,24 +1037,31 @@
</tr>
</tbody>
</table>
+
<para>The firing of that Activation results in a balance of 50.</para>
- <table border="0px">
+
+ <table border="0">
<tbody>
<tr>
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="2" align="left">Account</th>
+ <th align="left" colspan="2">Account</th>
</tr>
+
<tr align="center">
<th>accountNo</th>
+
<th>balance</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>1</td>
+
<td>50</td>
</tr>
</tbody>
@@ -807,15 +1070,19 @@
</tr>
</tbody>
</table>
- <para>So what happens if you don't want the order of Activation execution to be arbitrary?
- When there is one or more Activations on the Agenda they are said to be in conflict, and a
- conflict resolver strategy is used to determine the order of execution. At the simplest
- level the default strategy uses salience to determine rule priority. Each rule has a default
- value of 0, the higher the value the higher the priority. To illustrate this a rule to print
- the Account balance can be added, we want this rule to be executed after all the debit's and
- credit's have been applied for this rule, by setting the rule to have a salience of below 0
- we ensure it fires afterwards.</para>
- <table border="0px">
+
+ <para>So what happens if you don't want the order of Activation
+ execution to be arbitrary? When there is one or more Activations on the
+ Agenda they are said to be in conflict, and a conflict resolver strategy
+ is used to determine the order of execution. At the simplest level the
+ default strategy uses salience to determine rule priority. Each rule has
+ a default value of 0, the higher the value the higher the priority. To
+ illustrate this a rule to print the Account balance can be added, we
+ want this rule to be executed after all the debit's and credit's have
+ been applied for this rule, by setting the rule to have a salience of
+ below 0 we ensure it fires afterwards.</para>
+
+ <table border="0">
<tbody>
<tr>
<td>
@@ -831,36 +1098,50 @@
</tr>
</tbody>
</table>
- <para>The table below shows the resulting Agenda, the 3 debit and credit rules are shown to be
- arbitrary order, while the print rule is shown to execute aftwards.</para>
- <table border="0px">
+
+ <para>The table below shows the resulting Agenda, the 3 debit and credit
+ rules are shown to be arbitrary order, while the print rule is shown to
+ execute aftwards.</para>
+
+ <table border="0">
<tbody>
<tr>
<td align="left" valign="top">
- <table border="1" cellpadding="3" ccellspacing="0" style="border-style:solid; border-spacing:0; border-collapse:collapse">
+ <table border="1" ccellspacing="0" cellpadding="3"
+ style="border-style:solid; border-spacing:0; border-collapse:collapse">
<thead>
<tr>
- <th colspan="3" align="left">Agenda</th>
+ <th align="left" colspan="3">Agenda</th>
</tr>
</thead>
+
<tbody>
<tr>
<td>1</td>
+
<td>increase balance</td>
+
<td rowspan="3">arbitrary</td>
</tr>
+
<tr>
<td>2</td>
+
<td>decrease balance</td>
</tr>
+
<tr>
<td>3</td>
+
<td>increase balance</td>
</tr>
+
<tr>
<td>4</td>
+
<td>print balance</td>
- <td/>
+
+ <td />
</tr>
</tbody>
</table>
@@ -868,44 +1149,58 @@
</tr>
</tbody>
</table>
- <para>Earlier we showed how rules would equate to SQL, which can often be helpful for people
- with an SQL background when understanding rules. The two ruels above can be represented with
- two views and a trigger for each view, as below:</para>
- <table border="0px">
+
+ <para>Earlier we showed how rules would equate to SQL, which can often
+ be helpful for people with an SQL background when understanding rules.
+ The two ruels above can be represented with two views and a trigger for
+ each view, as below:</para>
+
+ <table border="0">
<tbody>
<tr>
<td align="left" valign="top">
<programlisting>select * from Account acc, Cashflow cf, AccountPeriod ap
where acc.accountNo == cf.accountNo and
- cf.type == CREDIT cf.date >= ap.start and
+ cf.type == CREDIT cf.date >= ap.start and
cf.date <= ap.end</programlisting>
</td>
+
<td align="left" valign="top">
<programlisting>select * from Account acc, Cashflow cf, AccountPeriod ap
where acc.accountNo == cf.accountNo and
- cf.type == DEBIT cf.date >= ap.start and
+ cf.type == DEBIT cf.date >= ap.start and
cf.date <= ap.end</programlisting>
</td>
</tr>
+
<tr>
<td align="left" valign="top">
<programlisting>trigger : acc.balance += cf.amount</programlisting>
</td>
+
<td align="left" valign="top">
<programlisting>trigger : acc.balance -= cf.amount</programlisting>
</td>
</tr>
</tbody>
</table>
- <para>Drools also features ruleflow-group attributes which allows workflow diagrams to
- declaratively specify when rules are allowed to fire. The screenshot below is taken from
- Eclipse using the Drools plugin. It has two ruleflow-group nodes that ensures the
- calculation rules are executed before the reporting rules.</para>
+
+ <para>Drools also features ruleflow-group attributes which allows
+ workflow diagrams to declaratively specify when rules are allowed to
+ fire. The screenshot below is taken from Eclipse using the Drools
+ plugin. It has two ruleflow-group nodes that ensures the calculation
+ rules are executed before the reporting rules.</para>
+
<mediaobject>
- <imageobject><imagedata fileref="images/Chapter-Quick_Start/ruleflow.png"/></imageobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Quick_Start/ruleflow.png" />
+ </imageobject>
</mediaobject>
- <para>The use of the ruleflow-group attribute in a rule is shown below.</para>
- <table border="0px">
+
+ <para>The use of the ruleflow-group attribute in a rule is shown
+ below.</para>
+
+ <table border="0">
<tbody>
<tr>
<td align="left" valign="top">
@@ -916,12 +1211,13 @@
acc : Account( $accountNo : accountNo )
CashFlow( type == CREDIT,
accountNo == $accountNo,
- date >= ap.start && <= ap.end,
+ date >= ap.start && <= ap.end,
$ammount : ammount )
then
acc.balance += $amount;
end</programlisting>
</td>
+
<td align="left" valign="top">
<programlisting>rule “Print blance for AccountPeriod”
ruleflow-group “report”
@@ -937,4 +1233,104 @@
</table>
</section>
</section>
+
+ <section>
+ <title></title>
+
+ <para></para>
+
+ <section>
+ <title>KnowledgeBase by Configuration using Changesets</title>
+
+ <para>The programmatic api has been used so far to build a
+ KnowledgeBase, quite often it's more desirable to this via
+ configuration. To facilitate this drools supports the changeset.xml
+ which contains a list of resources, it's recursive so it can actually
+ also point to other changeset.xml. Currently the changeset has a single
+ "add" element, support for remove and modify will be added in the future
+ for more powerful incremental changes over time. There is currently no
+ XSD for the xml, we hope to add one soon, so a few examples will be
+ shown to give the jist of things. A resource approach is used that uses
+ a prefix of the used protocol, it supports all the protocolols provided
+ by java.net.URL, such as file" and "http", as well as an additional
+ "classpath". Currently the type attribute must always be specified for a
+ resource, it is not inferred from the file name extension. Here is a
+ simple example that points to a http location for some rules.</para>
+
+ <programlisting> <change-set xmlns='http://drools.org/drools-5.0/change-set'
+ xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
+ xs:schemaLocation='http://drools.org/drools-5.0/change-set drools-change-set-5.0.xsd' >
+ <add>
+ <resource source='http:org/domain/myrules.drl' type='DRL' />
+ </add>
+ </change-set>
+</programlisting>
+
+ <para>To use the above xml the code is almost identical as before,
+ except we change the ResourceType to CHANGE_SET.</para>
+
+ <programlisting>KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+kbuilder.add( ResourceFactory.newClasspathResource( "myChangeSet.xml", getClass() ),
+ ResourceType.CHANGE_SET );
+if ( kbuilder.hasErrors() ) {
+ System.err.println( builder.getErrors().toString() );
+} </programlisting>
+
+ <para>Change sets can include any number of resources and even supports
+ additional configuration information, which currently is only needed for
+ decision tables. Below the example is expanded to load the rules from a
+ http url location and an excel decision table from the classpath.</para>
+
+ <programlisting> <change-set xmlns='http://drools.org/drools-5.0/change-set'
+ xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
+ xs:schemaLocation='http://drools.org/drools-5.0/change-set drools-change-set-5.0.xsd' >
+ <add>
+ <resource source='http:org/domain/myrules.drl' type='DRL' />
+ <resource source='classpath:data/IntegrationExampleTest.xls' type="DTABLE">
+ <decisiontable-conf input-type="XLS" worksheet-name="Tables_2" />
+ </resource>
+ </add>
+ </change-set>
+</programlisting>
+
+ <para>It is also possible to specify a directory, where the contents of
+ that directory will be added, it is expected that all the contents are
+ of the type specified, type is not yet inferred from file name
+ extensions.</para>
+
+ <programlisting> <change-set xmlns='http://drools.org/drools-5.0/change-set'
+ xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
+ xs:schemaLocation='http://drools.org/drools-5.0/change-set drools-change-set-5.0.xsd' >
+ <add>
+ <resource source='file://myfolder/' type='DRL' />
+ </add>
+ </change-set>
+</programlisting>
+ </section>
+
+ <section>
+ <title>Knowledge Agent</title>
+
+ <para>The KnowlegeAgent provides automatic loading, caching and
+ re-loading, of resources and is configured from a properties files. The
+ KnowledgeAgent can update or rebuild this KnowlegeBase as the resources
+ it uses are changed. The strategy for this is determined by the
+ configuration given to the factory, but it is typically pull based using
+ regular polling. We hope to add push based updates and rebuilds in
+ future versions. </para>
+
+ <programlisting>KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" );
+kagent.applyChangeSet( ResourceFactory.newUrlResource( url ) );
+KnowledgeBase kbase = kagent.getKnowledgeBase();</programlisting>
+
+ <para>The KnowledgeAgent will continously scan all the added resources,
+ using a default polling of 60s, and if their last modified date is
+ updated it will rebuild the cached KnowledgeBase using the new
+ resources. Note the previous KnowledgeBase reference will still exist
+ and you'll have to call getKnowledgeBase() to accessly the newly built
+ KnowledgeBase. If a directory is specified as part of the change set,
+ the entire contents of that directory will be scanned for
+ changes.</para>
+ </section>
+ </section>
</chapter>
More information about the jboss-svn-commits
mailing list