[jboss-svn-commits] JBL Code SVN: r26061 - in labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US: Chapter-Authoring and 7 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Thu Apr 16 07:52:32 EDT 2009
Author: mark.proctor at jboss.com
Date: 2009-04-16 07:52:31 -0400 (Thu, 16 Apr 2009)
New Revision: 26061
Added:
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Authoring/
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Authoring/Chapter-Authoring.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-IDE/Chapter-QuickStart (2).xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Chapter-Introduction.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Section-What_is_a_Rule_Engine.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Section-Why_use_a_Rule_Engine.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Chapter-Language_Reference.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Comments.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-DSL.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-ErrorMessages.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Function.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Keywords.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Overview.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Package.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Query.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Rule.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-TypeDeclaration.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-XML.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-A_Little_More_Theory.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-More_On_Building_And_Deploying.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Theory/
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Theory/Chapter-Theory.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Chapter-User_Guide.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Building.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Deploying.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Running.xml
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/Section-The_Basics.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Chapter-Rule_Engine.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Section-Rules.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Section-What_is_a_Rule_Engine.xml
labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/master.xml
Log:
-more expert docs
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Authoring/Chapter-Authoring.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Authoring/Chapter-Authoring.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Authoring/Chapter-Authoring.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,814 @@
+<?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"
+ xmlns:db="http://docbook.org/ns/docbook">
+ <title>Authoring</title>
+
+ <section xml:base="../../">
+ <title>Decision tables in spreadsheets</title>
+
+ <para>Decision tables are a "precise yet compact" (ref. Wikipedia) way of
+ representing conditional logic, and are well suited to
+ <emphasis>business</emphasis> level rules.</para>
+
+ <para>Drools supports managing rules in a Spreadsheet format. Formats
+ supported are Excel, and CSV. Meaning that a variety of spreadsheet
+ programs (such as Microsoft Excel, OpenOffice.org Calc amongst others) can
+ be utalized. It is expected that web based decision table editors will be
+ included in a near future release.</para>
+
+ <para>Decision tables are an old concept (in software terms) but have
+ proven useful over the years. Very briefly speaking, in Drools decision
+ tables are a way to generate rules driven from the data entered into a
+ spreadsheet. All the usual features of a spreadsheet for data capture and
+ manipulation can be taken advantage of.</para>
+
+ <section>
+ <title>When to use Decision tables</title>
+
+ <para>Decision tables my want to be considered as a course of action if
+ rules exist that can be expressed as rule templates + data. In each row
+ of a decision table, data is collected that is combined with the
+ templates to generate a rule.</para>
+
+ <para>Many businesses already use spreadsheets for managing data,
+ calculations etc. If you are happy to continue this way, you can also
+ manage your business rules this way. This also assumes you are happy to
+ manage packages of rules in .xls or .csv files. Decision tables are not
+ recommenced for rules that do not follow a set of templates, or where
+ there are a small number of rules (or if there is a dislike towards
+ software like excel or open office). They are ideal in the sense that
+ there can be control over what <emphasis>parameters</emphasis> of rules
+ can be edited, without exposing the rules directly.</para>
+
+ <para>Decision tables also provide a degree of insulation from the
+ underlying object model.</para>
+ </section>
+
+ <section>
+ <title>Overview</title>
+
+ <para>Here are some examples of real world decision tables (slightly
+ edited to protect the innocent).</para>
+
+ <screenshot>
+ <screeninfo>Using excel to edit a decision table</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/excel.png"
+ format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <screenshot>
+ <screeninfo>Can have multiple actions for a rule row</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/actions.png" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <screenshot>
+ <screeninfo>Using OpenOffice</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/open_office.png" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>In the above examples, the technical aspects of the decision table
+ have been collapsed away (standard spreadsheet feature).</para>
+
+ <para>The rules start from row 17 (each row results in a rule). The
+ conditions are in column C, D, E etc.. (off screen are the actions). The
+ value in the cells are quite simple, and have meaning when looking at
+ the headers in Row 16. Column B is just a description. It is
+ conventional to use color to make it obvious what the different areas of
+ the table mean.</para>
+
+ <note>
+ <para>Note that although the decision tables look like they process
+ top down, this is not necessarily the case. Idealy, if the rules are
+ able to be authored in such a way as order does not matter (simply as
+ it makes maintenance easier, as rows will not need to be shifted
+ around all the time).</para>
+ </note>
+
+ <para>As each row is a rule, the same principles apply. As the rule
+ engine processes the facts, any rules that match may fire (some people
+ are confused by this. It is possible to clear the agenda when a rule
+ fires and simulate a very simple decision table where the first match
+ exists). Also note that you can have multiple tables on the one
+ spreadsheet (so rules can be grouped where they share common templates,
+ yet at the end of the day they are all combined into a one rule
+ package). Decision tables are essentially a tool to generate DRL rules
+ automatically.</para>
+
+ <screenshot>
+ <screeninfo>A real world example using multiple tables for grouping
+ like rules</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/multi_table.png" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+ </section>
+
+ <section>
+ <title>How decision tables work</title>
+
+ <para>The key point to keep in mind is that in a decision table, each
+ row is a rule, and each column in that row is either a condition or
+ action for that rule.</para>
+
+ <screenshot>
+ <screeninfo>Rows and columns</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/row_col.png" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>The spreadsheet looks for the <firstterm>RuleTable</firstterm>
+ keyword to indicate the start of a rule table (both the starting row and
+ column). Other keywords are also used to define other package level
+ attributes (covered later). It is important to keep the keywords in the
+ one column. By convention the second column ("B") is used for this, but
+ it can be any column (convention is to leave a margin on the left for
+ notes). In the following diagram, C is actually the column where it
+ starts. Everything to the left of this is ignored.</para>
+
+ <para>If we expand the hidden sections, it starts to make more sense how
+ it works; note the keywords in column C.</para>
+
+ <screenshot>
+ <screeninfo>Expanded for rule templates</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/expanded.png" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>Now the hidden magic which makes it work can be seen. The RuleSet
+ keyword indicates the name to be used in the <emphasis>rule
+ package</emphasis> that all the rules will come under (the name is
+ optional, it will have a default but it MUST have the
+ <emphasis>RuleSet</emphasis> keyword) in the cell immediately to the
+ right.</para>
+
+ <para>The other keywords visible in Column C are: Import, Sequential
+ which will be covered later. The RuleTable keyword is important as it
+ indicates that a chunk of rules will follow, based on some rule
+ templates. After the RuleTable keyword there is a name - this name is
+ used to prefix the generated rules names (the row numbers are appended
+ to create unique rule names). The column of RuleTable indicates the
+ column in which the rules start (columns to the left are
+ ignored).</para>
+
+ <note>
+ <para>In general the keywords make up name/value pairs.</para>
+ </note>
+
+ <para>Referring to row 14 (the row immediately after RuleTable): the
+ keywords CONDITION and ACTION indicate that the data in the columns
+ below are for either the LHS or the RHS parts of a rule. There are other
+ attributes on the rule which can also be optionally set this way.</para>
+
+ <para>Row 15 contains declarations of <firstterm>ObjectTypes</firstterm>
+ ; the content in this row is optional (if this option is not in use, a
+ blank row must be left, however this option is usually found to be quite
+ useful). When using this row, the values in the cells below (row 16)
+ become constraints on that object type. In the above case, it will
+ generate: Person(age=="42") etc (where 42 comes from row 18). In the
+ above example, the "==" is implicit (if just a field name is given it
+ will assume that it is to look for exact matches).</para>
+
+ <note>
+ <para>An ObjectType declaration can span columns (via merged cells),
+ meaning that all columns below the merged range will be combined into
+ the one set of constraints.</para>
+ </note>
+
+ <para>Row 16 contains the rule templates themselves. They can use the
+ "$para" place holder to indicate where data from the cells below will be
+ populated ($param can be sued or $1, $2 etc to indicate parameters from
+ a comma separated list in a cell below). Row 17 is ignored as it is
+ textual descriptions of the rule template.</para>
+
+ <para>Row 18 to 19 shows data, which will be combined (interpolated)
+ with the templates in row 15, to generate rules. If a cell contains no
+ data, then its template is ignored (eg it means that condition, or
+ action, does not apply for that rule-row). Rule rows are read until
+ there is a BLANK row. Multiple RuleTables can exsist in a sheet. Row 20
+ contains another keyword, and a value. The row positions of keywords
+ like this do not matter (most people put them at the top) but their
+ column should be the same one where the RuleTable or RuleSet keywords
+ should appear (in this case column C has been chosen to be significant,
+ but column A could be used instead).</para>
+
+ <para>In the above example, rules would be rendered like the following
+ (as it uses the "ObjectType" row):</para>
+
+ <screen>//row 18
+ rule "Cheese_fans_18"
+ when
+ Person(age=="42")
+ Cheese(type=="stilton")
+ then
+ list.add("Old man stilton");
+ end
+</screen>
+
+ <note>
+ <para>The [age=="42"] and [type=="stilton"] are interpreted as single
+ constraints to be added to the respective ObjectType in the cell above
+ (if the cells above were spanned, then there could be multiple
+ constraints on one "column".</para>
+ </note>
+ </section>
+
+ <section>
+ <title>Keywords and syntax</title>
+
+ <section>
+ <title>Syntax of templates</title>
+
+ <para>The syntax of what goes in the templates is dependent on if it
+ is a CONDITION column or ACTION column. In most cases, it is identical
+ to <emphasis>vanilla</emphasis> DRL for the LHS or RHS respectively.
+ This means in the LHS, the constraint language must be used, and in
+ the RHS it is a snippet of code to be executed.</para>
+
+ <para>The <code>$param</code> place holder is used in templates to
+ indicate where data form the cell will be interpolated. You can also
+ use <code>$1</code> to the same effect. If the cell contains a comma
+ separated list of values, $1 and $2 etc. may be used to indicate which
+ positional parameter from the list of values in the cell will be
+ used.</para>
+
+ <example>
+ <para>If the templates is [Foo(bar == $param)] and the cell is [ 42
+ ] then the result will be [Foo(bar == 42)] If the template is
+ [Foo(bar < $1, baz == $2)] and the cell is [42,42] then the
+ result will be [Foo(bar > 42, baz ==42)]</para>
+ </example>
+
+ <para>For conditions: How snippets are rendered depends on if there is
+ anything in the row above (where ObjectType declarations may appear).
+ If there is, then the snippets are rendered as individual constraints
+ on that ObjectType. If there isn't, then they are just rendered as is
+ (with values substituted). If just a plain field is entered (as in the
+ example above) then it will assume this means equality. If another
+ operator is placed at the end of the snippet, then the values will put
+ interpolated at the end of the constraint, otherwise it will look for
+ <code>$param</code> as outlined previously.</para>
+
+ <para>For consequences: How snippets are rendered also depends on if
+ there is anything in the row immediately above it. If there is nothing
+ there, the output is simple the interpolated snippets. If there is
+ something there (which would typically be a bound variable or a global
+ like in the example above) then it will append it as a method call on
+ that object (refer to the above example).</para>
+
+ <para>This may be easiest to understand with some examples below.
+ <screenshot>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/spanned_column.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </screenshot> The above shows how the Person ObjectType declaration
+ spans 2 columns in the spreadsheet, thus both constraints will appear
+ as Person(age == ... , type == ...). As before, as only the field
+ names are present in the snippet, they imply an equality test.
+ <screenshot>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/with_param.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </screenshot> The above condition example shows how you use
+ interpolation to place the values in the snippet (in this case it
+ would result in Person(age == "42")).<screenshot>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/operator_completion.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </screenshot> The above condition example show that if you put an
+ operator on the end by itself, the values will be placed after the
+ operator automatically. <screenshot>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/with_binding.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </screenshot> A binding can be put in before the column (the
+ constraints will be added from the cells below). Anything can be
+ placed in the ObjectType row (eg it could be a pre condition for the
+ columns in the spreadsheet columns that follow).<screenshot>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/consequence.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </screenshot> This shows how the consequence could be done the by
+ simple interpolation (just leave the cell above blank, the same
+ applies to condition columns). With this style anything can be placed
+ in the consequence (not just one method call).</para>
+ </section>
+
+ <section>
+ <title>Keywords</title>
+
+ <para>The following table describes the keywords that are pertinent to
+ the rule table structure.</para>
+
+ <table>
+ <title>Keywords</title>
+
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Keyword</entry>
+
+ <entry>Description</entry>
+
+ <entry>Inclusion Status</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>RuleSet</entry>
+
+ <entry>The cell to the right of this contains the ruleset
+ name</entry>
+
+ <entry>One only (if left out, it will default)</entry>
+ </row>
+
+ <row>
+ <entry>Sequential</entry>
+
+ <entry>The cell to the right of this can be true or false. If
+ true, then salience is used to ensure that rules fire from the
+ top down</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>Import</entry>
+
+ <entry>The cell to the right contains a comma separated list
+ of Java classes to import</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>RuleTable</entry>
+
+ <entry>A cell starting with RuleTable indicates the start of a
+ definition of a rule table. The actual rule table starts the
+ next row down. The rule table is read left-to-right, and
+ top-down, until there is one BLANK ROW.</entry>
+
+ <entry>at least one. if there are more, then they are all
+ added to the one ruleset</entry>
+ </row>
+
+ <row>
+ <entry>CONDITION</entry>
+
+ <entry>Indicates that this column will be for rule
+ conditions</entry>
+
+ <entry>At least one per rule table</entry>
+ </row>
+
+ <row>
+ <entry>ACTION</entry>
+
+ <entry>Indicates that this column will be for rule
+ consequences</entry>
+
+ <entry>At least one per rule table</entry>
+ </row>
+
+ <row>
+ <entry>PRIORITY</entry>
+
+ <entry>Indicates that this columns values will set the
+ 'salience' values for the rule row. Over-rides the
+ 'Sequential' flag.</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>DURATION</entry>
+
+ <entry>Indicates that this columns values will set the
+ duration values for the rule row.</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>NAME</entry>
+
+ <entry>Indicates that this columns values will set the name
+ for the rule generated from that row</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>Functions</entry>
+
+ <entry>The cell immediately to the right can contain functions
+ which can be used in the rule snippets. Drools supports
+ functions defined in the DRL, allowing logic to be embedded in
+ the rule, and changed without hard coding, use with care. Same
+ syntax as regular DRL.</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>Variables</entry>
+
+ <entry>The cell immediately to the right can contain global
+ declarations which Drools supports. This is a type, followed
+ by a variable name. (if multiple variables are needed, comma
+ separate them).</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>No-loop or Unloop</entry>
+
+ <entry>Placed in the header of a table, no-loop or unloop will
+ both complete the same function of not allowing a rule (row)
+ to loop. For this option to function correctly, there must be
+ a value (true or false) in the cell for the option to take
+ effect. If the cell is left blank then this option will not be
+ set for the row.</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>XOR-GROUP</entry>
+
+ <entry>Cell values in this column mean that the rule-row
+ belongs to the given XOR/activation group . An Activation
+ group means that only one rule in the named group will fire
+ (ie the first one to fire cancels the other rules
+ activations).</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>AGENDA-GROUP</entry>
+
+ <entry>Cell values in this column mean that the rule-row
+ belongs to the given agenda group (that is one way of
+ controlling flow between groups of rules - see also "rule
+ flow").</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>RULEFLOW-GROUP</entry>
+
+ <entry>Cell values in this column mean that the rule-row
+ belongs to the given rule-flow group.</entry>
+
+ <entry>optional</entry>
+ </row>
+
+ <row>
+ <entry>Worksheet</entry>
+
+ <entry>By default, the first worksheet is only looked at for
+ decision tables.</entry>
+
+ <entry>N/A</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>Below you will find examples of using the HEADER keywords, which
+ effects the rules generated for each row. Note that the header name is
+ what is important in most cases. If no value appears in the cells
+ below it, then the attribute will not apply (it will be ignored) for
+ that specific row.</para>
+
+ <screenshot>
+ <screeninfo>Example usage of keywords for imports, headers etc..
+ etc.</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/Key.png" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>The following is an example of Import (comma delimited),
+ Variables (gloabls) - also comma delimited, and a function block (can
+ be multiple functions - just the usual drl syntax). This can appear in
+ the same column as the "RuleSet" keyword, and can be below all the
+ rule rows if you desire.</para>
+
+ <screenshot>
+ <screeninfo>Example usage of keywords forfunctions etc.</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/keywords.png" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+ </section>
+ </section>
+
+ <section>
+ <title>Creating and integrating Spreadsheet based Decision
+ Tables</title>
+
+ <para>The API to use spreadsheet based decision tables is in the
+ drools-decisiontables module. There is really only one class to look at:
+ SpreadsheetCompiler. This class will take spreadsheets in various
+ formats, and generate rules in DRL (which you can then use in the normal
+ way). The SpreadsheetComiler can just be used to generate partial rule
+ files if it is wished, and assemble it into a complete rule package
+ after the fact (this allows the seperation of technical and
+ non-technical aspects of the rules if needed).</para>
+
+ <para>To get started, a sample spreadsheet can be used as base.
+ Alternatively, if the plug-in is being used (Rule Workbench IDE), the
+ wizard can generate a spreadsheet from a template (to edit it an xls
+ compatible spreadsheet editor will need to be used). <screenshot>
+ <screeninfo>Wizard in the IDE</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/wizard.png" />
+ </imageobject>
+ </mediaobject>
+ </screenshot></para>
+ </section>
+
+ <section>
+ <title>Managing business rules in decision tables.</title>
+
+ <section>
+ <title>Workflow and collaboration.</title>
+
+ <para>Spreadsheets are well established business tools (in use for
+ over 25 years). Decision tables lend themselves to close collaboration
+ between IT and domain experts, while making the business rules clear
+ to business analysts, it is an ideal separation of concerns.</para>
+
+ <para>Typically, the whole process of authoring rules (coming up with
+ a new decision table) would be something like:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Business analyst takes a template decision table (from a
+ repository, or from IT)</para>
+ </listitem>
+
+ <listitem>
+ <para>Decision table business language descriptions are entered in
+ the table(s)</para>
+ </listitem>
+
+ <listitem>
+ <para>Decision table rules (rows) are entered (roughly)</para>
+ </listitem>
+
+ <listitem>
+ <para>Decision table is handed to a technical resource, who maps
+ the business language (descriptions) to scripts (this may involve
+ software development of course, if it is a new application or data
+ model)</para>
+ </listitem>
+
+ <listitem>
+ <para>Technical person hands back and reviews the modifications
+ with the business analyst.</para>
+ </listitem>
+
+ <listitem>
+ <para>The business analyst can continue editing the rule rows as
+ needed (moving columns around is also fine etc).</para>
+ </listitem>
+
+ <listitem>
+ <para>In parallel, the technical person can develop test cases for
+ the rules (liaising with business analysts) as these test cases
+ can be used to verify rules and rule changes once the system is
+ running.</para>
+ </listitem>
+ </orderedlist>
+ </section>
+
+ <section>
+ <title>Using spreadsheet features</title>
+
+ <para>Features of applications like Excel can be used to provide
+ assistance in entering data into spreadsheets, such as validating
+ fields. Lists that are stored in other worksheets can bse used to
+ provide valid lists of values for cells, like in the following
+ diagram. <screenshot>
+ <screeninfo>Wizard in the IDE</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/lists.png" />
+ </imageobject>
+ </mediaobject>
+ </screenshot></para>
+
+ <para>Some applications provide a limited ability to keep a history of
+ changes, but it is recommended that an alternative means of revision
+ control is also used. When changes are being made to rules over time,
+ older versions are archived (many solutions exist for this which are
+ also open source, such as Subversion).
+ http://www.drools.org/Business+rules+in+decision+tables+explained</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Rule Templates</title>
+
+ <para>Related to decision tables (but not necessarily requiring a
+ spreadsheet) are "Rule Templates" (in the drools-templates module).
+ These use any tablular data source as a source of rule data - populating
+ a template to generate many rules. This can allow both for more flexible
+ spreadsheets, but also rules in existing databases, for instance (at the
+ cost of developing the template up front to generate the rules).</para>
+
+ <para>With Rule Templates the data is separated from the rule and there
+ are no restrictions on which part of the rule is data-driven. So whilst
+ you can do everything you could do in decision tables you can also do
+ the following:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>store your data in a database (or any other format)</para>
+ </listitem>
+
+ <listitem>
+ <para>conditionally generate rules based on the values in the
+ data</para>
+ </listitem>
+
+ <listitem>
+ <para>use data for any part of your rules (e.g. condition operator,
+ class name, property name)</para>
+ </listitem>
+
+ <listitem>
+ <para>run different templates over the same data</para>
+ </listitem>
+ </itemizedlist>
+
+ <section>
+ <title>A decision table-like example</title>
+
+ <para>As an example, a more classic decision table is shown, but
+ without any hidden rows for the rule meta data (so the spreadsheet
+ only contains the raw data to generate the rules).</para>
+
+ <screenshot>
+ <screeninfo>Template data</screeninfo>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Decision_Tables/template1.png" />
+ </imageobject>
+ </mediaobject>
+ </screenshot>
+
+ <para>See the "ExampleCheese.xls" in the examples download for the
+ above spreadsheet.</para>
+
+ <para>If this was a regular decision table there would be hidden rows
+ before row 1 and between rows 1 and 2 containing rule metadata. With
+ rule templates the data is completely separate from the rules. This
+ has two handy consequences - you can apply multiple rule templates to
+ the same data and your data is not tied to your rules at all. So what
+ does the template look like?</para>
+
+ <programlisting>
+1 template header
+2 age
+3 type
+4 log
+5
+6 package org.drools.examples.templates;
+7
+8 global java.util.List list;
+9
+10 template "cheesefans"
+11
+12 rule "Cheese fans_@{row.rowNumber}"
+13 when
+14 Person(age == @{age})
+15 Cheese(type == "@{type}")
+16 then
+17 list.add("@{log}");
+18 end
+19
+20 end template
+ </programlisting>
+
+ <para>Referring to the above:</para>
+
+ <programlisting>
+Line 1: all rule templates start with "template header"
+Lines 2-4: following the header is the list of columns in the order they appear in the data. In this case we are calling the first column "age", the second "type" and the third "log".
+Lines 5: empty line signifying the end of the column definitions
+Lines 6-9: standard rule header text. This is standard rule DRL and will appear at the top of the generated DRL. Put the package statement and any imports and global definitions
+Line 10: The "template" keyword signals the start of a rule template. There can be more than one template in a template file. The template should have a unique name.
+Lines 11-18: The rule template - see below
+Line 20: "end template" signifies the end of the template.
+</programlisting>
+
+ <para>The rule templates rely on MVEL to do substitution using the
+ syntax @{token_name}. There is currently one built-in expression,
+ @{row.rowNumber} which gives a unique number for each row of data and
+ enables you to generate unique rule names. For each row of data a rule
+ will be generated with the values in the data substituted for the
+ tokens in the template. With the example data above the following rule
+ file would be generated:</para>
+
+ <programlisting>
+package org.drools.examples.templates;
+
+global java.util.List list;
+
+rule "Cheese fans_1"
+when
+ Person(age == 42)
+ Cheese(type == "stilton")
+then
+ list.add("Old man stilton");
+end
+
+rule "Cheese fans_2"
+when
+ Person(age == 21)
+ Cheese(type == "cheddar")
+then
+ list.add("Young man cheddar");
+end
+</programlisting>
+
+ <para>The code to run this is simple:</para>
+
+ <programlisting>KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+DecisionTableConfiguration dtconf = KnowledgeBuilderFactory.newDecisionTableConfiguration();
+dtconf.setInputType( DecisionTableInputType.XLS );
+dtconf.setWorksheetName( "Tables_2" );
+kbuilder.add( ResourceFactory.newInputStreamResource( getSpreadsheetStream() ),
+ ResourceType.DTABLE,
+ dtconf );
+
+Collection<KnowlegePackage> kpkg = kbuilder.getKnowlegePackages();
+</programlisting>
+
+ <para>We create an ExternalSpreadsheetCompiler object and use it to
+ merge the spreadsheet with the rules. The two integer parameters
+ indicate the column and row where the data actually starts - in our
+ case column 2, row 2 (i.e. B2)</para>
+ </section>
+ </section>
+ </section>
+</chapter>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-IDE/Chapter-QuickStart (2).xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-IDE/Chapter-QuickStart (2).xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-IDE/Chapter-QuickStart (2).xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,765 @@
+<?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" xmlns:db="http://docbook.org/ns/docbook" xml:base="./">
+ <title>The (Eclipse based) Rule IDE</title>
+
+ <para>
+ The IDE provides developers (and very technical users) with an environment to edit and test rules in various formats, and integrate it deeply with their applications. In cases where you prefer business rules and web tooling, you will want to look at the BRMS (but using the BRMS and the IDE together is not uncommon).</para>
+
+ <para>The Drools IDE is delivered as an Eclipse plug-in, which
+ allows you to author and manage rules from within Eclipse, as well as
+ integrate rules with your application. This is an optional tool, and not all
+ components are required to be used, you can use what components are relevant
+ to you. The Drools IDE is also a part of the Red Hat Developer Studio (formerly known as JBoss IDE).</para>
+
+ <para>This guide will cover some of the features of JBoss Drools, in as far
+ as the IDE touches on them (it is assumed that the reader has some
+ familiarity with rule engines, and Drools in particular. It is important to
+ note that none of the underlying features of the rule engine are dependent
+ on Eclipse, and integrators are free to use their tools of choice, as always
+ ! Plenty of people use IntelliJ with rules, for instance.</para>
+
+ <para>Note you can get the plug-in either as a zip to download, or from an
+ update site (refer to the chapter on installation).</para>
+
+ <figure>
+ <title>Overview</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/all.jpg" format="JPG" scalefit="1" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <section>
+ <title>Features outline</title>
+
+ <para>The rules IDE has the following features</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Textual/graphical rule editor</para>
+
+ <orderedlist>
+ <listitem>
+ <para>An editor that is aware of DRL syntax, and provides content
+ assistance (including an outline view)</para>
+ </listitem>
+ <listitem>
+ <para>An editor that is aware of DSL (domain specific langauge) extensions, and provides content assistance.</para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+
+ <listitem>
+ <para>RuleFlow graphical editor</para>
+ <para>You can edit visual graphs which represent a process (a rule flow). The RuleFlow can then be applied to your rule package to have imperative control.</para>
+ </listitem>
+
+ <listitem>
+ <para>Wizards to accelerate and ...</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Help you quickly create a new "rules" project</para>
+ </listitem>
+
+ <listitem>
+ <para>Create a new rule resource</para>
+ </listitem>
+
+ <listitem>
+ <para>Create a new Domain Specific language</para>
+ </listitem>
+
+ <listitem>
+ <para>Create a new decision table, guided editor, ruleflow</para>
+ </listitem>
+
+
+ </orderedlist>
+ </listitem>
+
+ <listitem>
+ <para>A domain specific language editor</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Create and manage mappings from your users language to the
+ rule language</para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+
+ <listitem>
+ <para>Rule validation</para>
+
+ <orderedlist>
+ <listitem>
+ <para>As rules are entered, the rule is "built" in the background
+ and errors reported via the problem "view" where possible</para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+
+ <para>You can see the above features make use of Eclipse infrastructure
+ and features. All of the power of Eclipse is available.</para>
+ </section>
+
+ <section>
+ <title>Creating a Rule project</title>
+
+ <para>The aim of the new project wizard is to setup an executable scaffold
+ project to start using rules immediately. This will setup a basic
+ structure, classpath and sample rules and test case to get you
+ started.</para>
+
+ <figure>
+ <title>New rule project scaffolding</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/new_project1.jpg" format="JPG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>When you choose to create a new "rule project" - you will get a choice to add some default artifacts to it (like rules, decision tables, ruleflows etc). These can serve as a starting point, and will give you something executable to play with (which you can then modify and mould to your needs). The simplest case (a hello world rule) is shown below. Feel free to experiment with the plug-in at this point.</para>
+
+ <figure>
+ <title>New rule project result</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/new_project2.png" format="JPG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The newly created project contains an example rule file (Sample.drl)
+ in the src/rules dir and an example Java file (DroolsTest.Java) that can
+ be used to execute the rules in a Drools engine in the folder src/Java, in
+ the com.sample package. All the others jars that are necessary during
+ execution are also added to the classpath in a custom classpath container
+ called Drools Library. Rules do not have to be kept in "Java"
+ projects at all, this is just a convenience for people who are already
+ using Eclipse as their Java IDE.</para>
+
+ <para>Important note: The Drools plug-in adds a "Drools Builder"
+ capability to your Eclipse instance. This means you can enable a builder
+ on any project that will build and validate your rules when resources
+ change. This happens automatically with the Rule Project Wizard, but you
+ can also enable it manually on any project. One downside of this is if you
+ have rule files that have a large number of rules (>500 rules per file)
+ it means that the background builder may be doing a lot of work to
+ build the rules on each change. An option here is to turn off the builder,
+ or put the large rules into .rule files, where you can still use the rule
+ editor, but it won't build them in the background - to fully validate the
+ rules you will need to run them in a unit test of course.</para>
+ </section>
+
+ <section>
+ <title>Creating a new rule and wizards</title>
+
+ <para>You can create a rule simple as an empty text ".drl" file, or use
+ the wizard to do so. The wizard menu can be invoked by Control+N, or
+ choosing it from the toolbar (there will be a menu with the JBoss Drools
+ icon).</para>
+
+ <figure>
+ <title>The wizard menu</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/wizards.jpg" format="JPG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The wizard will ask for some basic options for generating a rule
+ resource. These are just hints, you can change your mind later !. In terms
+ of location, typically you would create a top level /rules directory to
+ store your rules if you are creating a rule project, and store it in a
+ suitably named subdirectory. The package name is mandatory, and is similar
+ to a package name in Java (ie. its a namespace that groups like rules
+ together).</para>
+
+ <figure>
+ <title>New rule wizard</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/new_rule.jpg" format="JPG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>This result of this wizard is to generate a rule skeleton to work
+ from. As with all wizards, they are candy: you don't have to use them if
+ you don't want !</para>
+ </section>
+
+ <section>
+ <title>Textual rule editor</title>
+
+ <para>The rule editor is where rule managers and developers will be
+ spending most of their time. The rule editor follows the pattern of a
+ normal text editor in Eclipse, with all the normal features of a text
+ editor. On top of this, the rule editor provides pop up content
+ assistance. You invoke popup content assistance the "normal" way by
+ pressing Control + Space at the same time.</para>
+
+ <figure>
+ <title>The rule editor in action</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/editor1.jpg" format="JPG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The rule editor works on files that have a .drl (or .rule)
+ extension. Rules are generally grouped together as a "package" of rules
+ (like the old ruleset construct). It will also be possible to have rules
+ in individual files (grouped by being in the same package "namespace" if
+ you like). These DRL files are plain text files.</para>
+
+ <para>You can see from the example above that the package is using a
+ domain specific language (note the expander keyword, which tells the rule
+ compiler to look for a dsl file of that name, to resolve the rule
+ language). Even with the domain specific language (DSL) the rules are
+ still stored as plain text as you see on screen, which allows simpler
+ management of rules and versions (comparing versions of rules for
+ instance).</para>
+
+ <para>The editor has an outline view that is kept in sync with the
+ structure of the rules (updated on save). This provides a quick way of
+ navigating around rules by name, in a file which may have hundreds of
+ rules. The items are sorted alphabetically by default.</para>
+
+ <figure>
+ <title>The rule outline view</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/outline.jpg" format="JPG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </section>
+
+<section>
+ <title>Guided editor (rule GUI)</title>
+ <para>
+ A new feature of the Drools IDE (since version 4) is the guided editor for rules. This is similar to the web based editor that is available in the BRMS. This allows you to build rules in a GUI driven fashion, based on your object model.
+ </para>
+
+ <figure>
+ <title>The guided editor</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/guidededitor1.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>
+ To create a rule this way, use the wizard menu. It will create a instance of a .brl file and open an editor. The guided editor works based on a .package file in the same directory as the .brl file. In this "package" file - you have the package name and import statements - just like you would in the top of a normal DRL file. So the first time you create a brl rule - you will need to ppulate the package file with the fact classes you are interested in. Once you have this the guided editor will be able to prompt you with facts/fields and build rules graphically.
+ </para>
+
+ <para>
+ The guided editor works off the model classes (fact classes) that you configure. It then is able to "render" to DRL the rule that you have entered graphically. You can do this visually - and use it as a basis for learning DRL, or you can use it and build rules of the brl directly. To do this, you can either use the drools-ant module (it is an ant task that will build up all the rule assets in a folder as a rule package - so you can then deploy it as a binary file), OR you can use the following snippet of code to convert the brl to a drl rule:
+
+ </para>
+
+ <programlisting>BRXMLPersitence read = BRXMLPersitence.getInstance();
+BRDRLPersistence write = BRDRLPersistence.getInstance();
+String brl = ... read from the .brl file as needed...
+String outputDRL = write.marshall(read.unmarshal(brl));
+//then pass the outputDRL to the PackageBuilder as normal</programlisting>
+</section>
+
+ <section>
+ <title>Views</title>
+
+ <para>When debugging an application using a Drools engine, these views
+ can be used to check the state of the Drools engine itself: the Working
+ Memory View, the Agenda View the Global Data View. To be able to use
+ these views, create breakpoints in your code invoking the working memory.
+ For example, the line where you call workingMemory.fireAllRules() is a
+ good candidate. If the debugger halts at that joinpoint, you should select
+ the working memory variable in the debug variables view. The following
+ rules can then be used to show the details of the selected working
+ memory:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>The Working Memory shows all elements in the working memory of
+ the Drools working memory.</para>
+ </listitem>
+
+ <listitem>
+ <para>The Agenda View shows all elements on the agenda. For each rule
+ on the agenda, the rule name and bound variables are shown.</para>
+ </listitem>
+
+ <listitem>
+ <para>The Global Data View shows all global data currently defined in
+ the Drools working memory.</para>
+ </listitem>
+ </orderedlist>
+
+ <para>The Audit view can be used to show audit logs that contain events
+ that were logged during the execution of a rules engine in a tree
+ view.</para>
+
+ <section>
+ <title>The Working Memory View</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-IDE/workingMemory.png" />
+ </imageobject>
+ </mediaobject>
+
+ <para>The Working Memory shows all elements in the working memory of the
+ Drools engine.</para>
+
+ <para>An action is added to the right of the view, to customize what is
+ shown:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>The Show Logical Structure toggles showing the logical
+ structure of the elements in the working memory, or all their
+ details. Logical structures allow for example visualizing sets of
+ elements in a more obvious way.</para>
+ </listitem>
+ </orderedlist>
+ </section>
+
+ <section>
+ <title>The Agenda View</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-IDE/agenda.png" />
+ </imageobject>
+ </mediaobject>
+
+ <para>The Agenda View shows all elements on the agenda. For each rule on
+ the agenda, the rule name and bound variables are shown.</para>
+
+ <para>An action is added to the right of the view, to customize what is
+ shown:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>The Show Logical Structure toggles showing the logical
+ structure of the agenda item, or all their details. Logical
+ structures allow for example visualizing sets of elements in a more
+ obvious way. The logical structure of AgendaItems shows the rule
+ that is represented by the AgendaItem, and the values of all the
+ parameters used in the rule.</para>
+ </listitem>
+ </orderedlist>
+ </section>
+
+ <section>
+ <title>The Global Data View</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-IDE/globals.png" />
+ </imageobject>
+ </mediaobject>
+
+ <para>The Global Data View shows all global data currently defined in
+ the Drools engine.</para>
+
+ <para>An action is added to the right of the view, to customize what is
+ shown:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>The Show Logical Structure toggles showing the logical
+ structure of the elements in the working memory, or all their
+ details. Logical structures allow for example visualizing sets of
+ elements in a more obvious way.</para>
+ </listitem>
+ </orderedlist>
+ </section>
+
+ <section>
+ <title>The Audit View</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-IDE/audit.jpg" scalefit="1" width="100%" />
+ </imageobject>
+ </mediaobject>
+
+ <para>The audit view can be used to visualize an audit log that can be
+ created when executing the rules engine. To create an audit log, use the
+ following code:</para>
+
+ <programlisting> WorkingMemory workingMemory = ruleBase.newWorkingMemory();
+ // create a new Working Memory Logger, that logs to file.
+ WorkingMemoryFileLogger logger = new WorkingMemoryFileLogger(workingMemory);
+ // an event.log file is created in the log dir (which must exist)
+ // in the working directory
+ logger.setFileName("log/event");
+
+ workingMemory.assertObject( ... );
+ workingMemory.fireAllRules();
+
+ // stop logging
+ logger.writeToDisk();</programlisting>
+
+ <para>Open the log by clicking the Open Log action (first action in the
+ Audit View) and select the file. The Audit view now shows all events
+ that where logged during the executing of the rules. There are different
+ types of events (each with a different icon):</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Object inserted (green square)</para>
+ </listitem>
+
+ <listitem>
+ <para>Object updated (yellow square)</para>
+ </listitem>
+
+ <listitem>
+ <para>Object removed (red square)</para>
+ </listitem>
+
+ <listitem>
+ <para>Activation created (arrow to the right)</para>
+ </listitem>
+
+ <listitem>
+ <para>Activation cancelled (arrow to the left)</para>
+ </listitem>
+
+ <listitem>
+ <para>Activation executed (blue diamond)</para>
+ </listitem>
+
+ <listitem>
+ <para>Ruleflow started / ended (process icon)</para>
+ </listitem>
+
+ <listitem>
+ <para>Ruleflow-group activated / deactivated (process icon)</para>
+ </listitem>
+
+ <listitem>
+ <para>Rule package added / removed (Drools icon)</para>
+ </listitem>
+
+ <listitem>
+ <para>Rule added / removed (Drools icon)</para>
+ </listitem>
+ </orderedlist>
+
+ <para>All these events show extra information concerning the event, like
+ the id and toString representation of the object in case of working
+ memory events (assert, modify and retract), the name of the rule and all
+ the variables bound in the activation in case of an activation event
+ (created, cancelled or executed). If an event occurs when executing an
+ activation, it is shown as a child of the activation executed event. For
+ some events, you can retrieve the "cause":</para>
+
+ <orderedlist>
+ <listitem>
+ <para>The cause of an object modified or retracted event is the last
+ object event for that object. This is either the object asserted
+ event, or the last object modified event for that object.</para>
+ </listitem>
+
+ <listitem>
+ <para>The cause of an activation cancelled or executed event is the
+ corresponding activation created event.</para>
+ </listitem>
+ </orderedlist>
+
+ <para>When selecting an event, the cause of that event is shown in green
+ in the audit view (if visible of course). You can also right click the
+ action and select the "Show Cause" menu item. This will scroll you to
+ the cause of the selected event.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Domain Specific Languages</title>
+
+ <para>Domain Specific Languages (dsl) allow you to create a language that
+ allows your rules to look like... rules ! Most often the domain specific
+ language reads like natural language. Typically you would look at how a
+ business analyst would describe the rule, in their own words, and then map
+ this to your object model via rule constructs. A side benefit of this is
+ that it can provide an insulation layer between your domain objects, and
+ the rules themselves (as we know you like to refactor !). A domain
+ specific language will grow as the rules grow, and works best when there
+ are common terms used over an over, with different parameters.</para>
+
+ <para>To aid with this, the rule workbench provides an editor for domain
+ specific languages (they are stored in a plain text format, so you can
+ use any editor of your choice - it uses a slightly enhanced version of the
+ "Properties" file format, simply). The editor will be invoked on any files
+ with a .dsl extension (there is also a wizard to create a sample
+ DSL).</para>
+
+ <section>
+ <title>Editing languages</title>
+
+ <figure>
+ <title>The Domain Specific Language editor</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/dsl_editor.jpg" format="JPG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The DSL editor provides a table view of Language Expression to
+ Rule Expression mapping. The Language expression is what is used in the
+ rules. This also feeds the content assistance for the rule editor, so
+ that it can suggest Language Expressions from the DSL configuration (the
+ rule editor loads up the DSL configuration when the rule resource is
+ loaded for editing). The Rule language mapping is the "code" for the
+ rules - which the language expression will be compiled to by the rule
+ engine compiler. For form of this Rule language depends if it is for a
+ condition or action part of a rule (it may be a snippet of Java, for
+ instance). The "scope" item indicates where the expression is targeted:
+ is it for the "when" part of the rule (LHS)? the "then" part (RHS)? Or
+ anywhere?</para>
+
+ <para>By selecting a mapping item (a row in the table) you can see the
+ expression and mapping in the greyed out fields below. Double clicking
+ or pressing the edit button will open the edit dialog. You can remove
+ items, and add new ones (you should generally only remove when you know
+ that expression is no longer in use).</para>
+
+ <figure>
+ <title>Language Mapping editor dialog</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/mapping_editor.jpg"
+ format="JPG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>How it works: the "Language expression" is used to parse the rule
+ language, depending on what the "scope" is set to. When it is found in a
+ rule, the values that are market by the curly braces {value} are
+ extracted from the rule source. These values are then interpolated with
+ the "Rule mapping" expression, based on the names between the curly
+ braces. So in the example above, the natural language expression maps
+ to 2 constraints on a fact of type Person (ie the person object has the
+ age field as less than {age}, and the location value is the string of
+ {value}, where {age} and {value} are pulled out of the original rule
+ source. The Rule mapping may be a Java expression (such as if the scope
+ was "then"). If you did not wish to use a language mapping for a
+ particular rule in a drl, prefix the expression with > and the
+ compiler will not try to translate it according to the language
+ definition. Also note that domain specific languages are optional. When
+ the rule is compiled, the .dsl file will also need to be
+ available.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>The Rete View</title>
+
+ <para>The Rete Tree View shows you the current Rete Network for your drl
+ file. Just click on the tab "Rete Tree" below on the DRL Editor.
+ Afterwards you can generate the current Rete Network visualization. You
+ can push and pull the nodes to arrange your optimal network overview. If
+ you got hundreds of nodes, select some of them with a frame. Then you can
+ pull groups of them. You can zoom in and out, in case not all nodes are
+ shown in the current view. For this press the button "+" oder "-".</para>
+
+ <para>There is no export function, which creates a gif or jpeg picture, in
+ the current release. Please use ctrl + alt + print to create a copy of
+ your current Eclipse window and cut it off.</para>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-IDE/thereteview.jpg" />
+ </imageobject>
+ </mediaobject>
+
+ <para>The Rete View is
+ an advanced feature which takes full advantage of the Eclipse Graphical Editing Framework (GEF).</para>
+
+ <para>The Rete view works only in Drools Rule Projects, where the Drools
+ Builder is set in the project´s properties.</para>
+
+ <para>If you are using Drools in an other type of project, where you are
+ not having a Drools Rule Project with the appropriate Drools Builder, you
+ can create a little workaround:</para>
+
+ <para>Set up a little Drools Rule Project next to it, putting needed
+ libraries into it and the drls you want to inspect with the Rete View.
+ Just click on the right tab below in the DRL Editor, followed by a click
+ on "Generate Rete View".</para>
+ </section>
+
+ <section>
+ <title>Large drl files</title>
+
+ <para>Depending on the JDK you use, it may be necessary to increase the
+ permanent generation max size. Both SUN and IBM jdk have a permanent
+ generation, whereas BEA JRockit does not.</para>
+
+ <para>To increase the permanent generation, start Eclipse with
+ -XX:MaxPermSize=###m</para>
+
+ <para>Example: c:\Eclipse\Eclipse.exe -XX:MaxPermSize=128m</para>
+
+ <para>Rulesets of 4,000 rules or greater should set the permanent
+ generation to atleast 128Mb.</para>
+
+ <para>(note that this may also apply to compiling large numbers of rules
+ in general - as there is generally one or more classes per rule).</para>
+
+ <para>As an alternative to the above, you may put rules in a file with the
+ ".rule" extension, and the background builder will not try to compile them
+ with each change, which may provide performance improvements if your IDE
+ becomes sluggish with very large numbers of rules.</para>
+ </section>
+
+
+ <section>
+
+ <title>Debugging rules</title>
+
+ <figure>
+ <title>Debugging</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/debug-overview.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>You can debug rules during the execution of your Drools application.
+ You can add breakpoints in the consequences of your rules, and whenever
+ such a breakpoint is uncounted during the execution of the rules, the execution
+ is halted. You can then inspect the variables known at that point and use any
+ of the default debugging actions to decide what should happen next (step over,
+ continue, etc.). You can also use the debug views to inspect the content of the
+ working memory and agenda.</para>
+
+<section>
+ <title>Creating breakpoints</title>
+ <para>You can add/remove rule breakpoints in drl files in two ways, similar to adding
+ breakpoints to Java files:</para>
+ <orderedlist>
+ <listitem>
+ <para>Double-click the ruler of the DRL editor at the line where you want to
+ add a breakpoint. Note that rule breakpoints can only be created in the
+ consequence of a rule. Double-clicking on a line where no breakpoint is allowed
+ will do nothing. A breakpoint can be removed by double-clicking the ruler once more.
+ </para>
+ </listitem>
+ <listitem>
+ <para>If you right-click the ruler, a popup menu will show up, containing the
+ "Toggle breakpoint" action. Note that rule breakpoints can only be created in the
+ consequence of a rule. The action is automatically disabled if no rule
+ breakpoint is allowed at that line. Clicking the action will add a breakpoint at the
+ selected line, or remove it if there was one already.</para>
+ </listitem>
+ </orderedlist>
+ <para>The Debug Perspective contains a Breakpoints view which can be used to see
+ all defined breakpoints, get their properties, enable/disable or remove them, etc.</para>
+</section>
+<section>
+ <title>Debugging rules</title>
+ <para>Drools breakpoints are only enabled if you debug your application as
+ a Drools Application. You can do this like this:</para>
+
+ <figure>
+ <title>Debug as Drools Application</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/debugAsDrools.png" format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <orderedlist>
+ <listitem>
+ <para>Select the main class of your application. Right click it and select the
+ "Debug As >" sub-menu and select Drools Application. Alternatively, you can also select
+ the "Debug ..." menu item to open a
+ new dialog for creating, managing and running debug configurations (see
+ screenshot below)</para>
+ <orderedlist>
+ <listitem>
+ <para>Select the "Drools Application" item in the left tree and click the "New
+ launch configuration" button (leftmost icon in the toolbar above the tree). This
+ will create a new configuration and already fill in some of the properties
+ (like the project and main class) based on main class you selected in the beginning.
+ All properties shown here are the same as any standard Java program.</para>
+ </listitem>
+ <listitem>
+ <para>Change the name of your debug configuration to something meaningful.
+ You can just accept the defaults for all other properties. For more information
+ about these properties, please check the Eclipse jdt documentation.</para>
+ </listitem>
+ <listitem>
+ <para>Click the "Debug" button on the bottom to start debugging your application. You only have to define your debug configuration once. The next time you try to run your Drools application, you don't have to create a new one but select the one you defined previously by selecting it in the tree on the left, as a sub-element of the "Drools Application"
+ tree node, and then click the Debug button. The Eclipse toolbar also contains shortcut
+ buttons to quickly re-execute the one of your previous configurations (at least when the
+ Java, Java Debug, or Drools perspective has been selected).
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </orderedlist>
+
+ <figure>
+ <title>Debug as Drools Application Configuration</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/debug_rules_configuration.png" format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>After clicking the "Debug" button, the application starts executing and will halt if any
+ breakpoint is encountered. This can be a Drools rule breakpoint, or any other standard
+ Java breakpoint. Whenever a Drools rule breakpoint is encountered, the corresponding drl
+ file is opened and the active line is highlighted. The Variables view also contains all rule
+ parameters and their value. You can then use the default Java debug actions
+ to decide what to do next (resume, terminate, step over, etc.). The debug views can also
+ be used to determine the contents of the working memory and agenda at that time as well
+ (you don't have to select a working memory now, the current executing working memory
+ is automatically shown).
+ </para>
+
+ <figure>
+ <title>Debugging</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-IDE/debug.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ </section>
+ </section>
+
+
+</chapter>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Chapter-Introduction.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Chapter-Introduction.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Chapter-Introduction.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,25 @@
+<?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" xmlns:db="http://docbook.org/ns/docbook">
+ <title>The Rule Engine</title>
+
+ <xi:include href="Section-What_is_a_Rule_Engine.xml" />
+
+ <xi:include href="Section-Why_use_a_Rule_Engine.xml" />
+
+ <!--xi:include href="Section-Rules.xml" />
+
+ <xi:include href="Section-Rete_Algorithm.xml" /-->
+
+ <!--xi:include href="Section-The_Drools_Rule_Engine.xml" /-->
+
+ <!--xi:include href="Chapter-Rule_Engine/Section-Rule_Base.xml" />
+
+ <xi:include href="Chapter-Rule_Engine/Section-Working_Memory.xml" />
+
+ <xi:include href="Chapter-Rule_Engine/Section-Agenda.xml" />
+
+ <xi:include href="Chapter-Rule_Engine/Section-Event_Model.xml" /-->
+</chapter>
\ No newline at end of file
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Section-What_is_a_Rule_Engine.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Section-What_is_a_Rule_Engine.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Section-What_is_a_Rule_Engine.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
+ <title>What is a Rule Engine?</title>
+
+ <section>
+ <title>Introduction and Background</title>
+
+ <para>Artificial Intelligence (A.I.) is a very broad research area that
+ focuses on "Making computers think like people" and includes disciplines
+ such as Neural Networks, Genetic Algorithms, Decision Trees, Frame Systems
+ and Expert Systems. Knowledge representation is the area of A.I. concerned
+ with how knowledge is represented and manipulated. Expert Systems use
+ Knowledge representation to facilitate the codification of knowledge into
+ a knowledge base which can be used for reasoning, i.e., we can process
+ data with this knowledge base to infer conclusions. Expert Systems are
+ also known as Knowledge-based Systems and Knowledge-based Expert Systems
+ and are considered to be "applied artificial intelligence". The process of
+ developing with an Expert System is Knowledge Engineering. EMYCIN was one
+ of the first "shells" for an Expert System, which was created from the
+ MYCIN medical diagnosis Expert System. Whereas early Expert Systems had
+ their logic hard-coded, "shells" separated the logic from the system,
+ providing an easy to use environment for user input. Drools is a Rule
+ Engine that uses the rule-based approach to implement an Expert System and
+ is more correctly classified as a Production Rule System.</para>
+
+ <para>The term "Production Rule" originates from formal grammars where it
+ is described as "an abstract structure that describes a formal language
+ precisely, i.e., a set of rules that mathematically delineates a (usually
+ infinite) set of finite-length strings over a (usually finite) alphabet"
+ (<ulink url="http://en.wikipedia.org/wiki/Formal_grammar">
+ <citetitle>wikipedia</citetitle>
+ </ulink>).</para>
+
+ <para>Business Rule Management Systems build additional value on top of a
+ general purpose Rule Engine by providing business user focused systems for
+ rule creation, management, deployment, collaboration, analysis and end
+ user tools. Further adding to this value is the fast evolving and popular
+ methodology "Business Rules Approach", which is a helping to formalize the
+ role of Rule Engines in the enterprise.</para>
+
+ <para>The term Rule Engine is quite ambiguous in that it can be any system
+ that uses rules, in any form, that can be applied to data to produce
+ outcomes. This includes simple systems like form validation and dynamic
+ expression engines. The book "How to Build a Business Rules Engine (2004)"
+ by Malcolm Chisholm exemplifies this ambiguity. The book is actually about
+ how to build and alter a database schema to hold validation rules. The
+ book then shows how to generate VB code from those validation rules to
+ validate data entry. This, while a very valid and useful topic for some,
+ caused quite a surprise to this author, unaware at the time in the
+ subtleties of Rules Engines' differences, who was hoping to find some
+ hidden secrets to help improve the Drools engine. JBoss jBPM uses
+ expressions and delegates in its Decision nodes which control the
+ transitions in a Workflow. At each node it evaluates ther is a rule set
+ that dictates the transition to undertake, and so this is also a Rule
+ Engine. While a Production Rule System is a kind of Rule Engine and also
+ an Expert System, the validation and expression evaluation Rule Engines
+ mentioned previously are not Expert Systems.</para>
+
+ <para>A Production Rule System is Turing complete, with a focus on
+ knowledge representation to express propositional and first order logic in
+ a concise, non-ambiguous and declarative manner. The brain of a Production
+ Rules System is an Inference Engine that is able to scale to a large
+ number of rules and facts. The Inference Engine matches facts and data
+ against Production Rules - also called Productions or just Rules - to
+ infer conclusions which result in actions. A Production Rule is a two-part
+ structure using First Order Logic for reasoning over knowledge
+ representation.</para>
+
+ <programlisting role="JAVA">when
+ <conditions>
+then
+ <actions>;</programlisting>
+
+ <para>The process of matching the new or existing facts against Production
+ Rules is called <indexterm>
+ <primary>Pattern Matching</primary>
+ </indexterm> Pattern Matching, which is performed by the <indexterm>
+ <primary>Inference Engine</primary>
+ </indexterm> Inference Engine. There are a number of algorithms used for
+ Pattern Matching by Inference Engines including:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Linear</para>
+ </listitem>
+
+ <listitem>
+ <para>Rete</para>
+ </listitem>
+
+ <listitem>
+ <para>Treat</para>
+ </listitem>
+
+ <listitem>
+ <para>Leaps</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Drools implements and extends the <indexterm>
+ <primary>Rete</primary>
+ </indexterm> Rete algorithm;<indexterm>
+ <primary>Leaps</primary>
+ </indexterm> Leaps used to be provided but was retired as it became
+ unmaintained. The Drools <indexterm>
+ <primary>Rete</primary>
+ </indexterm> Rete implementation is called ReteOO, signifying that
+ Drools has an enhanced and optimized implementation of the Rete algorithm
+ for object oriented systems. Other Rete based engines also have marketing
+ terms for their proprietary enhancements to Rete, like RetePlus and Rete
+ III. The most common enhancements are covered in "Production Matching for
+ Large Learning Systems (Rete/UL)" (1995) by Robert B. Doorenbos.</para>
+
+ <para>The Rules are stored in the <indexterm>
+ <primary>Production Memory</primary>
+ </indexterm> Production Memory and the facts that the Inference Engine
+ matches against are kept in the <indexterm>
+ <primary>WorkingMemory</primary>
+ </indexterm> Working Memory. Facts are asserted into the Working Memory
+ where they may then be modified or retracted. A system with a large number
+ of rules and facts may result in many rules being true for the same fact
+ assertion; these rules are said to be in conflict. The Agenda manages the
+ execution order of these conflicting rules using a Conflict Resolution
+ strategy.</para>
+
+ <figure>
+ <title>High-level View of a Rule Engine</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" contentdepth="300px" contentwidth="540px"
+ fileref="images/Chapter-Rule_Engine/rule-engine-inkscape.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>There are two methods of execution for a rule system: Forward
+ Chaining and Backward Chaining; systems that implement both are called
+ Hybrid Rule Systems. Understanding these two modes of operation is the key
+ to understanding why a Production Rule System is different and how to get
+ the best from it. Forward chaining is "data-driven" and thus reactionary,
+ with facts being asserted into working memory, which results in one or
+ more rules being concurrently true and scheduled for execution by the
+ Agenda. In short, we start with a fact, it propagates and we end in a
+ conclusion. Drools is a forward chaining engine.</para>
+
+ <figure>
+ <title>Forward Chaining</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Forward_Chaining.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Backward chaining is "goal-driven", meaning that we start with a
+ conclusion which the engine tries to satisfy. If it can't it then searches
+ for conclusions that it can satisfy; these are known as subgoals, that
+ will help satisfy some unknown part of the current goal. It continues this
+ process until either the initial conclusion is proven or there are no more
+ subgoals. Prolog is an example of a Backward Chaining engine; Drools plans
+ to provide support for Backward Chaining in a future release.</para>
+
+ <figure>
+ <title>Backward Chaining</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Backward_Chaining.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Section-Why_use_a_Rule_Engine.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Section-Why_use_a_Rule_Engine.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Introduction/Section-Why_use_a_Rule_Engine.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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"
+ xmlns:db="http://docbook.org/ns/docbook" xml:base="../../">
+ <title>Why use a Rule Engine?</title>
+
+ <para>Some frequently asked questions:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>When should you use a rule engine?</para>
+ </listitem>
+
+ <listitem>
+ <para>What advantage does a rule engine have over hand coded
+ "if...then" approaches?</para>
+ </listitem>
+
+ <listitem>
+ <para>Why should you use a rule engine instead of a scripting framework,
+ like <indexterm>
+ <primary>BeanShell</primary>
+ </indexterm> BeanShell?</para>
+ </listitem>
+ </orderedlist>
+
+ <para>We will attempt to address these questions below.</para>
+
+ <section>
+ <title>Advantages of a Rule Engine</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>Declarative Programming</para>
+
+ <para>Rule engines allow you to say "What to do", not "How to do
+ it".</para>
+
+ <para>The key advantage of this point is that using rules can make it
+ easy to express solutions to difficult problems and consequently have
+ those solutions verified. Rules are much easier to read than
+ code.</para>
+
+ <para>Rule systems are capable of solving very, very hard problems,
+ providing an explanation of how the solution was arrived at and why
+ each "decision" along the way was made (not so easy with other of AI
+ systems like neural networks or the human brain - I have no idea why I
+ scratched the side of the car).</para>
+ </listitem>
+
+ <listitem>
+ <para>Logic and Data Separation</para>
+
+ <para>Your data is in your domain objects, the logic is in the rules.
+ This is fundamentally breaking the OO coupling of data and logic,
+ which can be an advantage or a disadvantage depending on your point of
+ view. The upshot is that the logic can be much easier to maintain as
+ there are changes in the future, as the logic is all laid out in
+ rules. This can be especially true if the logic is cross-domain or
+ multi-domain logic. Instead of the logic being spread across many
+ domain objects or controllers, it can all be organized in one or more
+ very distinct rules files.</para>
+ </listitem>
+
+ <listitem>
+ <para>Speed and Scalability</para>
+
+ <para>The Rete algorithm,the Leaps algorithm, and their descendants such as
+ Drools' ReteOO, provide very efficient ways of matching
+ rule patterns to your domain object data. These are especially
+ efficient when you have datasets that change in small portions as the
+ rule engine can remember past matches. These algorithms are battle
+ proven.</para>
+ </listitem>
+
+ <listitem>
+ <para>Centralization of Knowledge</para>
+
+ <para>By using rules, you create a repository of knowledge (a
+ knowledge base) which is executable. This means it's a single point of
+ truth, for business policy, for instance. Ideally rules are so
+ readable that they can also serve as documentation.</para>
+ </listitem>
+
+ <listitem>
+ <para>Tool Integration</para>
+
+ <para>Tools such as Eclipse (and in future, Web based user interfaces)
+ provide
+ ways to edit and manage rules and get immediate feedback, validation
+ and content assistance. Auditing and debugging tools are also
+ available.</para>
+ </listitem>
+
+ <listitem>
+ <para>Explanation Facility</para>
+
+ <para>Rule systems effectively provide an "explanation facility" by
+ being able to log the decisions made by the rule engine along with why
+ the decisions were made.</para>
+ </listitem>
+
+ <listitem>
+ <para>Understandable Rules</para>
+
+ <para>By creating object models and, optionally, Domain Specific
+ Languages that model your problem domain you can set yourself up to
+ write rules that are very close to natural language. They lend
+ themselves to logic that is understandable to, possibly nontechnical,
+ domain experts as they are expressed in their language, with all the
+ program plumbing, the technical know-how being hidden
+ away in the usual code.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>When should you use a Rule Engine?</title>
+
+ <para>The shortest answer to this is "when there is no satisfactory
+ traditional programming approach to solve the problem.". Given that short
+ answer, some more explanation is required. The reason why there is no
+ "traditional" approach is possibly one of the following: <itemizedlist>
+ <listitem>
+ <para>The problem is just too fiddle for traditional code.</para>
+
+ <para>The problem may not be complex, but you can't see a
+ non-fragile way of building a solution for it.</para>
+ </listitem>
+
+ <listitem>
+ <para>The problem is beyond any obvious algorithmic
+ solution.</para>
+
+ <para>It is a complex problem to solve, there are no obvious
+ traditional solutions, or basically the problem isn't fully
+ understood.</para>
+ </listitem>
+
+ <listitem>
+ <para>The logic changes often</para>
+
+ <para>The logic itself may even be simple but
+ the rules change quite often. In many organizations software
+ releases are few and far between and pluggable rules can help provide the
+ "agility" that is needed and expected in a reasonably safe
+ way.</para>
+ </listitem>
+
+ <listitem>
+ <para>Domain experts (or business analysts) are readily available,
+ but are nontechnical.</para>
+
+ <para>Domain experts often possess a wealth of knowledge about business
+ rules and processes. They typically are nontechnical, but can be
+ very logical. Rules can allow them to express the logic in their own
+ terms. Of course, they still have to think critically and be capable
+ of logical thinking. Many people in nontechnical positions do
+ not have training in formal logic, so be careful and work with them,
+ as by codifying business knowledge in rules, you will often expose
+ holes in the way the business rules and processes are currently
+ understood.</para>
+ </listitem>
+ </itemizedlist></para>
+
+ <para>If rules are a new technology for your project teams, the overhead
+ in getting going must be factored in. It is not a trivial technology, but
+ this document tries to make it easier to understand.</para>
+
+ <para>Typically in a modern OO application you would use a rule engine to
+ contain key parts of your business logic,
+ <emphasis>especially the really messy parts</emphasis>. This is
+ an inversion of the OO concept of encapsulating all the logic inside your
+ objects. This is not to say that you throw out OO practices, on the
+ contrary in any real world application, business logic is just one part of
+ the application. If you ever notice lots of conditional statements
+ such as "if" and "switch", an
+ overabundance of strategy patterns and other messy logic in your code
+ that just doesn't feel right: that would be a place for rules.
+ If there is some such logic and you keep coming back to fix it, either
+ because you got it wrong, or the logic or your understanding changes: think
+ about using rules. If you are faced with tough problems for which there are
+ no algorithms or patterns: consider using rules.</para>
+
+ <para>Rules could be used embedded in your application or perhaps as a
+ service. Often a rule engine works best as "stateful" component, being
+ an integral part of an application. However, there have been
+ successful cases of creating reusable rule services which are
+ stateless.</para>
+
+ <para>For your organization it is important to decide about the process you
+ will use for updating rules in systems that are in production. The options
+ are many, but different organizations have different requirements.
+ Frequently, rules maintenance is out of the control of the application
+ vendors or project developers.</para>
+ </section>
+
+ <section>
+ <title>When not to use a Rule Engine</title>
+
+ <para>To quote a Drools mailing list regular: <blockquote><attribution>Dave Hamu</attribution>
+<para>It seems to me
+ that in the excitement of working with rules engines, that people forget
+ that a rules engine is only one piece of a complex application or
+ solution. Rules engines are not really intended to handle workflow or
+ process executions nor are workflow engines or process management tools
+ designed to do rules. Use the right tool for the job. Sure, a pair of
+ pliers can be used as a hammering tool in a pinch, but that's not what
+ it's designed for.</para>
+</blockquote></para>
+
+ <para>As rule engines are dynamic (dynamic in the sense that the rules can
+ be stored and managed and updated as data), they are often looked at as a
+ solution to the problem of deploying software. (Most IT departments seem to
+ exist for the purpose of preventing software being rolled out.) If this is
+ the reason you wish to use a rule engine, be aware that rule engines work
+ best when you are able to write declarative rules. As an alternative, you
+ can consider data-driven designs (lookup tables), or script processing
+ engines where the scripts are managed in a database and are able to be
+ updated on the fly.</para>
+ </section>
+
+ <section>
+ <title>Scripting or Process Engines</title>
+
+ <para>Hopefully the preceding sections have explained when you may want to
+ use a rule engine.</para>
+
+ <para>Alternatives are script-based engines that provide the drive
+ for "changes on the fly", and there are many such solutions.</para>
+
+ <para>Alternatively Process Engines (also capable of workflow) such as
+ jBPM allow you to graphically (or programmatically) describe steps in a
+ process. Those steps can also involve decision points which are in
+ themselves a simple rule. Process engines and rules often can work nicely
+ together, so they are not mutually exclusive.</para>
+
+ <para>One key point to note with rule engines is that some rule engines
+ are really scripting engines. The downside of scripting engines is that
+ you are tightly coupling your application to the scripts. If they are
+ rules, you are effectively calling rules directly and this may cause more
+ difficulty in future maintenance, as they tend to grow in complexity over
+ time. The upside of scripting engines is that they can be easier to
+ implement initially, producing results quickly, and are conceptually
+ simpler for imperative programmers.</para>
+
+ <para>Many people have also implemented data-driven systems successfully
+ in the past (where there are control tables that store meta-data that
+ changes your applications behavior) - these can work well when the
+ control can remain very limited. However, they can quickly grow out of
+ control if extended too much (such that only the original creators can
+ change the applications behavior) or they cause the application to
+ stagnate as they are too inflexible.</para>
+ </section>
+
+ <section>
+ <title>Strong and Loose Coupling</title>
+
+ <para>No doubt you have heard terms like "tight coupling" and "loose
+ coupling" in systems design. Generally people assert that "loose" or
+ "weak" coupling is preferable in design terms, due to the added
+ flexibility it affords. Similarly, you can have "strongly coupled" and
+ "weakly coupled" rules. Strongly coupled in this sense means that one rule
+ "firing" will clearly result in another rule firing, and so on; in other
+ words,
+ there is a clear (probably obvious) chain of logic. If your rules are all
+ strongly coupled, the chances are that the will turn out to be inflexible,
+ and, more significantly, that a rule engine is an overkill. A clear chain
+ can be hard coded, or implemented using a Decision Tree. This is not to
+ say that strong
+ coupling is inherently bad, but it is a point to keep in mind when
+ considering a rule engine and the way you capture the rules. "Loosely"
+ coupled rules should result in a system that allows rules to be changed,
+ removed and added without requiring changes to other, unrelated
+ rules.</para>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Chapter-Language_Reference.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Chapter-Language_Reference.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Chapter-Language_Reference.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,32 @@
+<?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"
+ xmlns:db="http://docbook.org/ns/docbook" >
+ <title>The Rule Language</title>
+
+ <xi:include href="Section-Overview.xml" />
+
+ <xi:include href="Section-Keywords.xml" />
+
+ <xi:include href="Section-Comments.xml" />
+
+ <xi:include href="Section-ErrorMessages.xml" />
+
+ <xi:include href="Section-Package.xml" />
+
+ <xi:include href="Section-Function.xml" />
+
+ <xi:include href="Section-TypeDeclaration.xml" />
+
+ <xi:include href="Section-Rule.xml" />
+
+ <xi:include href="Section-Query.xml" />
+
+ <xi:include href="Section-DSL.xml" />
+
+ <xi:include href="Section-XML.xml" />
+ </chapter>
\ No newline at end of file
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Comments.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Comments.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Comments.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
+ <title>Comments</title>
+
+ <note>
+ <para><replaceable>(updated to Drools 4.0)</replaceable></para>
+ </note>
+
+ <para>Comments are sections of text that are ignored by the rule engine.
+ They are stripped out when they are encountered, except inside semantic code
+ blocks, like the RHS of a rule.</para>
+
+ <section>
+ <title>Single line comment</title>
+
+ <figure>
+ <title>Single line comment</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Language/single_line_comment.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>To create single line comments, you can use either '#' or '//'. The
+ parser will ignore anything in the line after the comment symbol.
+ Example:</para>
+
+ <programlisting>rule "Testing Comments"
+when
+ # this is a single line comment
+ // this is also a single line comment
+ eval( true ) # this is a comment in the same line of a pattern
+then
+ // this is a comment inside a semantic code block
+ # this is another comment in a semantic code block
+end
+</programlisting>
+ </section>
+
+ <section>
+ <title>Multi-line comment</title>
+
+ <figure>
+ <title>Multi-line comment</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Language/multi_line_comment.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Multi-line comments are used to comment blocks of text, both in and
+ outside semantic code blocks. Example:</para>
+
+ <programlisting>rule "Test Multi-line Comments"
+when
+ /* this is a multi-line comment
+ in the left hand side of a rule */
+ eval( true )
+then
+ /* and this is a multi-line comment
+ in the right hand side of a rule */
+end </programlisting>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-DSL.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-DSL.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-DSL.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,394 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <section 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"
+ xmlns:db="http://docbook.org/ns/docbook" xml:base="../../">
+ <title>Domain Specific Languages</title>
+
+ <para>As mentioned previously, <indexterm>
+ <primary>Domain Specific Languages</primary>
+ </indexterm>(or DSLs) are a way of extending the rule language to your
+ problem domain. They are wired in to the rule language for you, and can make
+ use of all the underlying rule language and engine features.</para>
+
+ <para>DSLs are used both in the IDE, as well as the web based BRMS. Of
+ course as rules are text, you can use them even without this tooling.</para>
+
+ <section>
+ <title>When to use a DSL</title>
+
+ <para>DSLs can serve as a layer of separation between rule authoring (and
+ rule authors) and the domain objects that the engine operates on. DSLs can
+ also act as "templates" of conditions or actions that are used over and
+ over in your rules, perhaps only with parameters changing each time. If
+ your rules need to be read and validated by less technical folk, (such as
+ Business Analysts) the DSLs are definitely for you. If the conditions or
+ consequences of your rules follow similar patterns which you can express
+ in a template. You wish to hide away your implementation details, and
+ focus on the business rule. You want to provide a controlled means of
+ editing rules based on pre-defined templates.</para>
+
+ <para>DSLs have no impact on the rules at runtime, they are just a
+ parse/compile time feature.</para>
+
+ <para>Note that Drools 4 DSLs are quite different from Drools 2 XML based
+ DSLs. It is still possible to do Drools 2 style XML languages - if you
+ require this, then take a look at the Drools 4 XML rule language, and
+ consider using XSLT to map from your XML language to the Drools 4 XML
+ language.</para>
+ </section>
+
+ <section>
+ <title>Editing and managing a DSL</title>
+
+ <para>A DSL's configuration like most things is stored in plain text. If
+ you use the IDE, you get a nice graphical editor (with some validation),
+ but the format of the file is quite simple, and is basically a properties
+ file.</para>
+
+ <para>Note that since Drools 4.0, DSLs have become more powerful in
+ allowing you to customise almost any part of the language, including
+ keywords. Regular expressions can also be used to match words/sentences if
+ needed (this is provided for enhanced localisation). However, not all
+ features are supported by all the tools (although you can use them, the
+ content assistance just may not be 100% accurate in certain cases).</para>
+
+ <example>
+ <title>Example <indexterm>
+ <primary>DSL</primary>
+ </indexterm> mapping</title>
+
+ <programlisting>[when]This is {something}=Something(something=={something})</programlisting>
+ </example>
+
+ <para>Referring to the above example, the [when] refers to the scope of
+ the expression: ie does it belong on the LHS or the RHS of a rule. The
+ part after the [scope] is the expression that you use in the rule
+ (typically a natural language expression, but it doesn't have to be). The
+ part on the right of the "=" is the mapping into the rule language (of
+ course the form of this depends on if you are talking about the RHS or the
+ LHS - if its the LHS, then its the normal LHS syntax, if its the RHS then
+ its fragments of Java code for instance).</para>
+
+ <para>The parser will take the expression you specify, and extract the
+ values that match where the {something} (named Tokens) appear in the
+ input. The values that match the tokens are then interpolated with the
+ corresponding {something} (named Tokens) on the right hand side of the
+ mapping (the target expression that the rule engine actually uses).</para>
+
+ <para>Note also that the "sentences" above can be regular expressions.
+ This means the parser will match the sentence fragements that match the
+ expressions. This means you can use (for instance) the '?' to indicate the
+ character before it is optional (think of each sentence as a regular
+ expression pattern - this means if you want to use regex characters - you
+ will need to escape them with a '\' of course.</para>
+
+ <para>It is important to note that the DSL expressions are processed one
+ line at a time. This means that in the above example, all the text after
+ "This is " to the end of the line will be included as the value for
+ "{something}" when it is interpolated into the target string. This may not
+ be exactly what you want, as you may want to "chain" together different
+ DSL expressions to generate a target expression. The best way around this
+ is to make sure that the {tokens} are enclosed with characters or words.
+ This means that the parser will scan along the sentence, and pluck out the
+ value BETWEEN the characters (in the example below they are
+ double-quotes). Note that the characters that surround the token are not
+ included in when interpolating, just the contents between them (rather
+ then all the way to the end of the line, as would otherwise be the
+ case).</para>
+
+ <para>As a rule of thumb, use quotes for textual data that a rule editor
+ may want to enter. You can also wrap words around the {tokens} to make
+ sure you enclose the data you want to capture (see other example).</para>
+
+ <example>
+ <title>Example with quotes</title>
+
+ <programlisting>[when]This is "{something}" and "{another}"=Something(something=="{something}", another=="{another}")
+[when]This is {also} valid=Another(something=="{also}")</programlisting>
+ </example>
+
+ <para>It is a good idea to try and avoid punctuation in your DSL
+ expressions where possible, other then quotes and the like - keep it
+ simple and things will be easier. Using a DSL can make debugging slightly
+ harder when you are first building rules, but it can make the maintenance
+ easier (and of course the readability of the rules).</para>
+
+ <para>The "{" and "}" characters should only be used on the left hand side
+ of the mapping (the expression) to mark tokens. On the right hand side you
+ can use "{" and "}" on their own if needed - such as <programlisting>if (foo) \{
+ doSomething();\ }</programlisting> as well as with the token names as shown
+ above.</para><para>PLEASE NOTE that if you want curly braces to appear literally as curly braces, then escape them with a backslack (\). Otherwise it may think it is a token to be replaced.
+ </para>
+ <para>Don't forget that if you are capturing strings from users, you will
+ also need the quotes on the right hand side of the mapping, just like a
+ normal rule, as the result of the mapping must be a valid expression in
+ the rule language.</para>
+
+ <example>
+ <title>Some more examples</title>
+
+ <programlisting>#This is a comment to be ignored.
+[when]There is a Person with name of "{name}"=Person(name=="{name}")
+[when]Person is at least {age} years old and lives in "{location}"=Person(age > {age}, location=="{location}")
+[then]Log "{message}"=System.out.println("{message}");
+[when]And = and</programlisting>
+ </example>
+
+ <para>Referring to the above examples, this would render the following
+ input as shown below: <example>
+ <title>Some examples as processed</title>
+
+ <programlisting>There is a Person with name of "kitty" ---> Person(name="kitty")
+Person is at least 42 years old and lives in "atlanta" ---> Person(age > 42, location="atlanta")
+Log "boo" ---> System.out.println("boo");
+There is a Person with name of "bob" and Person is at least 30 years old and lives in "atlanta"
+ ---> Person(name="kitty") and Person(age > 30, location="atlanta")</programlisting>
+ </example></para>
+ </section>
+
+ <section>
+ <title>Using a DSL in your rules</title>
+
+ <para>A good way to get started if you are new to Rules (and DSLs) is just
+ write the rules as you normally would against your object model. You can
+ unit test as you go (like a good agile citizen!). Once you feel
+ comfortable, you can look at extracting a domain language to express what
+ you are doing in the rules. Note that once you have started using the
+ "expander" keyword, you will get errors if the parser does not recognize
+ expressions you have in there - you need to move everything to the DSL. As
+ a way around this, you can prefix each line with ">" and it will tell
+ the parser to take that line literally, and not try and expand it (this is
+ handy also if you are debugging why something isn't working).</para>
+
+ <para>Also, it is better to rename the extension of your rules file from
+ ".drl" to ".dslr" when you start using DSLs, as that will allow the IDE to
+ correctly recognize and work with your rules file.</para>
+
+ <para>As you work through building up your DSL, you will find that the DSL
+ configuration stabilizes pretty quickly, and that as you add new rules and
+ edit rules you are reusing the same DSL expressions over and over. The aim
+ is to make things as fluent as possible.</para>
+
+ <para>To use the DSL when you want to compile and run the rules, you will
+ need to pass the DSL configuration source along with the rule source.
+ <programlisting>PackageBuilder builder = new PackageBuilder();
+builder.addPackageFromDrl( source, dsl );
+//source is a reader for the rule source, dsl is a reader for the DSL configuration
+</programlisting> You will also need to specify the expander by name in the
+ rule source file: <programlisting>expander your-expander.dsl
+</programlisting>Typically you keep the DSL in the same directory as the rule,
+ but this is not required if you are using the above API (you only need to
+ pass a reader). Otherwise everything is just the same.</para>
+
+ <para>You can chain DSL expressions together on one line, as long as it is
+ clear to the parser what the {tokens} are (otherwise you risk reading in
+ too much text until the end of the line). The DSL expressions are
+ processed according to the mapping file, top to bottom in order. You can
+ also have the resulting rule expressions span lines - this means that you
+ can do things like:</para>
+
+ <example>
+ <title>Chaining DSL Expressions</title>
+ <programlisting>There is a person called Bob who is happy
+ Or
+There is a person called Mike who is sad
+</programlisting>
+ </example>
+
+ <para>Of course this assumes that "Or" is mapped to the "or" conditional
+ element (which is a sensible thing to do).</para>
+ </section>
+
+ <section>
+ <title>Adding constraints to facts</title>
+
+ <para>A common requirement when writing rule conditions is to be able to
+ add many constraints to fact declarations. A fact may have many (dozens)
+ of fields, all of which could be used or not used at various times. To
+ come up with every combination as separate DSL statements would in many
+ cases not be feasible.</para>
+
+ <para>The DSL facility allows you to achieve this however, with a simple
+ convention. If your DSL expression starts with a "-", then it will be
+ assumed to be a field constraint, which will be added to the declaration
+ that is above it (one per line).</para>
+
+ <para>This is easier to explain with an example. Lets take look at Cheese
+ class, with the following fields: type, price, age, country. We can
+ express some LHS condition in normal DRL like the following
+ <programlisting>Cheese(age < 5, price == 20, type=="stilton", country=="ch")</programlisting>
+ If you know ahead of time that you will use all the fields, all the time,
+ it is easy to do a mapping using the above techniques. However, chances
+ are that you will have many fields, and many combinations. If this is the
+ case, you can setup your mappings like so: <programlisting>[when]There is a Cheese with=Cheese()
+[when]- age is less than {age}=age<{age}
+[when]- type is '{type}'=type=='{type}'
+[when]- country equal to '{country}'=country=='{country}'</programlisting></para>
+
+ <para><emphasis role="bold">IMPORTANT:</emphasis> It is NOT possible to
+ use the "-" feature after an <emphasis role="bold">accumulate</emphasis>
+ statement to add constraints to the accumulate pattern. This limitation
+ will be removed in the future.</para>
+
+ <para>You can then write rules with conditions like the following:
+ <programlisting>There is a Cheese with
+ - age is less than 42
+ - type is 'stilton'</programlisting> The parser will pick up the "-"
+ lines (they have to be on their own line) and add them as constraints to
+ the declaration above. So in this specific case, using the above mappings,
+ is the equivalent to doing (in DRL): <programlisting>Cheese(age<42, type=='stilton')</programlisting>
+ The parser will do all the work for you, meaning you just define mappings
+ for individual constraints, and can combine them how you like (if you are
+ using context assistant, if you press "-" followed by CTRL+space it will
+ conveniently provide you with a filtered list of field constraints to
+ choose from.</para>
+
+ <para>To take this further, after alter the DSL to have
+ [when][org.drools.Cheese]- age is less than {age} ... (and similar to all
+ the items in the example above).</para>
+
+ <para>The extra [org.drools.Cheese] indicates that the sentence only
+ applies for the main constraint sentence above it (in this case "There is
+ a Cheese with"). For example, if you have a class called "Cheese" - then
+ if you are adding contraints to the rule (by typing "-" and waiting for
+ content assistance) then it will know that only items marked as having an
+ object-scope of "com.yourcompany.Something" are valid, and suggest only
+ them. This is entirely optional (you can leave out that section if needed
+ - OR it can be left blank).</para>
+ </section>
+
+ <section>
+ <title>How it works</title>
+
+ <para>DSLs kick in when the rule is parsed. The DSL configuration is read
+ and supplied to the parser, so the parser can "expand" the DSL expressions
+ into the real rule language expressions.</para>
+
+ <para>When the parser is processing the rules, it will check if an
+ "expander" representing a DSL is enabled, if it is, it will try to expand
+ the expression based on the context of where it is the rule. If an
+ expression can not be expanded, then an error will be added to the
+ results, and the line number recorded (this insures against typos when
+ editing the rules with a DSL). At present, the DSL expander is fairly
+ space sensitive, but this will be made more tolerant in future releases
+ (including tolerance for a wide range of punctuation).</para>
+
+ <para>The expansion itself works by trying to match a line against the
+ expression in the DSL configuration. The values that correspond to the
+ token place holders are stored in a map based on the name of the token,
+ and then interpolated to the target mapping. The values that match the
+ token placeholders are extracted by either searching until the end of the
+ line, or until a character or word after the token place holder is
+ matched. The "{" and "}" are not included in the values that are
+ extracted, they are only used to demarcate the tokens - you should not use
+ these characters in the DSL expression (but you can in the target).</para>
+ </section>
+
+ <section>
+ <title>Creating a DSL from scratch</title>
+
+ <para>DSLs can be aid with capturing rules if the rules are well known,
+ just not in any technically usable format (ie. sitting around in people
+ brains). Until we are able to have those little sockets in our necks like
+ in the Matrix, our means of getting stuff into computers is still the old
+ fashioned way.</para>
+
+ <para>Rules engines require an object or a data model to operate on - in many
+ cases you may know this up front. In other cases the model will be
+ discovered with the rules. In any case, rules generally work better with
+ simpler flatter object models. In some cases, this may mean having a rule
+ object model which is a subset of the main applications model (perhaps
+ mapped from it). Object models can often have complex relationships and
+ hierarchies in them - for rules you will want to simplify and flatten the
+ model where possible, and let the rule engine infer relationships (as it
+ provides future flexibility). As stated previously, DSLs can have an
+ advantage of providing some insulation between the object model and the
+ rule language.</para>
+
+ <para>Coming up with a DSL is a collaborative approach for both technical
+ and domain experts. Historically there was a role called "knowledge
+ engineer" which is someone skilled in both the rule technology, and in
+ capturing rules. Over a short period of time, your DSL should stabilize,
+ which means that changes to rules are done entirely using the DSL. A
+ suggested approach if you are starting from scratch is the following
+ workflow: <itemizedlist>
+ <listitem>
+ <para>Capture rules as loose "if then" statements - this is really
+ to get an idea of size and complexity (possibly in a text
+ document).</para>
+ </listitem>
+
+ <listitem>
+ <para>Look for recurring statements in the rules captured. Also look
+ for the rule objects/fields (and match them up with what may already
+ be known of the object model).</para>
+ </listitem>
+
+ <listitem>
+ <para>Create a new DSL, and start adding statements from the above
+ steps. Provide the "holes" for data to be edited (as many statements
+ will be similar, with only some data changing).</para>
+ </listitem>
+
+ <listitem>
+ <para>Use the above DSL, and try to write the rules just like that
+ appear in the "if then" statements from the first and second steps.
+ Iterate this process until patterns appear and things stabilize. At
+ this stage, you are not so worried about the rule language
+ underneath, just the DSL.</para>
+ </listitem>
+
+ <listitem>
+ <para>At this stage you will need to look at the Objects, and the
+ Fields that are needed for the rules, reconcile this with the
+ datamodel so far.</para>
+ </listitem>
+
+ <listitem>
+ <para>Map the DSL statements to the rule language, based on the
+ object model. Then repeat the process. Obviously this is best done
+ in small steps, to make sure that things are on the right
+ track.</para>
+ </listitem>
+ </itemizedlist></para>
+ </section>
+
+ <section>
+ <title>Scope and keywords</title>
+
+ <para>If you are editing the DSL with the GUI, or as text, you will notice
+ there is a [scope] item at the start of each mapping line. This indicates
+ if the sentence/word applies to the LHS, RHS or is a keyword. Valid values
+ for this are [condition], [consequence] and [keyword] (with [when] and
+ [then] being the same as [condition] and [consequence] respectively). When
+ [keyword] is used, it means you can map any keyword of the language like
+ "rule" or "end" to something else. Generally this is only used when you
+ want to have a non English rule language (and you would ideally map it to
+ a single word).</para>
+ </section>
+
+ <section>
+ <title>DSLs in the BRMS and IDE</title>
+
+ <para>You can use DSLs in the BRMS in both guided editor rules, and
+ textual rules that use a dsl. (In fact, the same applies to the
+ IDE).</para>
+
+ <para>In the guided editor - the DSLs generally have to be simpler - what
+ you are doing is defining little "forms" to capture data from users in
+ text fields (ie as you pick a DSL expression - it will add an item to the
+ GUI which only allows you enter data in the {token} parts of a DSL
+ expression). You can not use sophisticated regular expressions to match
+ text. However, in textual rules (which have a .dslr extension in the IDE)
+ you are free to use the full power as needed.</para>
+
+ <para>In the BRMS - when you build a package the DSLs are already included
+ and all the work is done for you. In the IDE (or in any IDE) - you will
+ either need to use the drools-ant task, or otherwise use the code shown in
+ sections above.</para>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-ErrorMessages.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-ErrorMessages.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-ErrorMessages.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,326 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
+ <title>Error Messages</title>
+
+ <note>
+ <para><replaceable>(updated to Drools 5.0)</replaceable></para>
+ </note>
+
+ <para>Drools 5 introduces standardized error messages. This standardization
+ aims to help users to find and resolve problems in a easier and faster way.
+ In this section you will learn how to identify and interpret those error
+ messages, and you will also receive some tips on how to solve the problems
+ associated with them.</para>
+
+ <section>
+ <title>Message format</title>
+
+ <para>The standardization includes the error message format and to better
+ explain this format, let's use the following example:</para>
+
+ <figure>
+ <title>Error Message Format</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Language/error_message.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para><emphasis role="bold">1st Block:</emphasis> This area identifies the
+ error code.</para>
+
+ <para><emphasis role="bold">2nd Block:</emphasis> Line:column
+ information.</para>
+
+ <para><emphasis role="bold">3rd Block:</emphasis> Some text describing the
+ problem.</para>
+
+ <para><emphasis role="bold">4th Block:</emphasis> This is the first
+ context. Usually indicates the rule, function, template or query where the
+ error occurred. This block is not mandatory.</para>
+
+ <para><emphasis role="bold">5th Block:</emphasis> Identifies the pattern
+ where the error occurred. This block is not mandatory.</para>
+ </section>
+
+ <section>
+ <title>Error Messages Description</title>
+
+ <section>
+ <title>101: No viable alternative</title>
+
+ <para>Indicates the most common errors, where the parser came to a
+ decision point but couldn't identify an alternative. Here are some
+ examples:</para>
+
+ <example>
+ <programlisting>1: rule one
+2: when
+3: exists Foo()
+4: <emphasis role="bold">exits</emphasis> Bar()
+5: then
+6: end
+</programlisting>
+ </example>
+
+ <para>The above example generates this message:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>[ERR 101] Line 4:4 no viable alternative at input 'exits' in
+ rule one</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>At first glance this seems to be valid syntax, but it is not (exits
+ != exists). Let's take a look at next example:</para>
+
+ <example>
+ <programlisting>1: package org.drools;
+2: rule
+3: when
+4: Object()
+5: then
+6: System.out.println("A RHS");
+7: end
+</programlisting>
+ </example>
+
+ <para>Now the above code generates this message:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>[ERR 101] Line 3:2 no viable alternative at input
+ 'WHEN'</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>This message means that the parser could identify the <emphasis
+ role="bold">WHEN</emphasis> hard keyword, but it is not an option here.
+ In this case, it is missing the rule name.</para>
+
+ <para>No viable alternative error occurs also when you have lexical
+ problems. Here is a sample of a lexical problem:</para>
+
+ <example>
+ <programlisting>1: rule simple_rule
+2: when
+3: Student( name == "Andy )
+4: then
+5: end
+</programlisting>
+ </example>
+
+ <para>The above code misses to close the quotes and because of this the
+ parser generates this error message:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>[ERR 101] Line 0:-1 no viable alternative at input
+ '<eof>' in rule simple_rule in pattern Student</para>
+ </listitem>
+ </itemizedlist>
+
+ <tip>
+ <para>Usually the Line and Column information are accurate, but in
+ some cases (like unclosed quotes), the parser generates a 0:-1
+ position. In this case you should check whether you didn't forget to close
+ quotes, apostrophes or parentheses.</para>
+ </tip>
+ </section>
+
+ <section>
+ <title>102: Mismatched input</title>
+
+ <para>Indicates that the parser was looking for a particular symbol that
+ it didn’t find at the current input position. Here are some
+ samples:</para>
+
+ <example>
+ <programlisting>1: rule simple_rule
+2: when
+3: foo3 : Bar(
+</programlisting>
+ </example>
+
+ <para>The above example generates this message:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>[ERR 102] Line 0:-1 mismatched input '<eof>' expecting
+ ')' in rule simple_rule in pattern Bar</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>To fix this problem, it is necessary to complete the rule
+ statement.</para>
+
+ <tip>
+ <para>Usually when you get a 0:-1 position, it means that parser
+ reached the end of source.</para>
+ </tip>
+
+ <para>The following code generates more than one error message:</para>
+
+ <example>
+ <programlisting>1: package org.drools;
+2:
+3: rule "Avoid NPE on wrong syntax"
+4: when
+5: not( Cheese( ( type == "stilton", price == 10 ) || ( type == "brie", price == 15 ) ) from $cheeseList )
+6: then
+7: System.out.println("OK");
+8: end
+</programlisting>
+ </example>
+
+ <para>These are the errors associated with this source:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>[ERR 102] Line 5:36 mismatched input ',' expecting ')' in rule
+ "Avoid NPE on wrong syntax" in pattern Cheese</para>
+ </listitem>
+
+ <listitem>
+ <para>[ERR 101] Line 5:57 no viable alternative at input 'type' in
+ rule "Avoid NPE on wrong syntax"</para>
+ </listitem>
+
+ <listitem>
+ <para>[ERR 102] Line 5:106 mismatched input ')' expecting 'then' in
+ rule "Avoid NPE on wrong syntax"</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Note that the second problem is related to the first. To fix it,
+ just replace the commas (",") by AND operator ("&&").</para>
+
+ <tip>
+ <para>In some situations you can get more than one error message. Try to
+ fix one by one, starting at the first one. Some error messages are
+ generated merely as consequences of other errors.</para>
+ </tip>
+ </section>
+
+ <section>
+ <title>103: Failed predicate</title>
+
+ <para>A validating semantic predicate evaluated to false. Usually these
+ semantic predicates are used to identify soft keywords. This sample
+ shows exactly this situation:</para>
+
+ <example>
+ <programlisting> 1: package nesting;
+ 2: dialect "mvel"
+ 3:
+ 4: import org.drools.Person
+ 5: import org.drools.Address
+ 6:
+ 7: <emphasis role="bold">fdsfdsfds</emphasis>
+ 8:
+ 9: rule "test something"
+10: when
+11: p: Person( name=="Michael" )
+12: then
+13: p.name = "other";
+14: System.out.println(p.name);
+15: end
+</programlisting>
+ </example>
+
+ <para>With this sample, we get this error message:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>[ERR 103] Line 7:0 rule 'rule_key' failed predicate:
+ {(validateIdentifierKey(DroolsSoftKeywords.RULE))}? in rule</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The <emphasis role="bold">fdsfdsfds</emphasis> text is invalid and
+ the parser couldn’t identify it as the soft keyword "rule".</para>
+
+ <tip>
+ <para>This error is very similar to 102: Mismatched input, but usually
+ involves soft keywords.</para>
+ </tip>
+ </section>
+
+ <section>
+ <title>104: Trailing semi-colon not allowed</title>
+
+ <para>This error is associated with the "eval" clause, where its
+ expression may not be terminated with a semi-colon. Check this
+ example:</para>
+
+ <example>
+ <programlisting>1: rule simple_rule
+2: when
+3: eval(abc();)
+4: then
+5: end
+</programlisting>
+ </example>
+
+ <para>Due to the trailing semi-colon within eval, we get this error
+ message:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>[ERR 104] Line 3:4 trailing semi-colon not allowed in rule
+ simple_rule</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>This problem is simple to fix: just remove the
+ semi-colon.</para>
+ </section>
+
+ <section>
+ <title>105: Early Exit</title>
+
+ <para>The recognizer came to a (..)+ EBNF subrule that must match an
+ alternative at least once, but the subrule did not match anything.
+ Simply put: the parser has entered a branch from where there is no
+ way out. This example tries to illustrates it:</para>
+
+ <example>
+ <programlisting>1: template test_error
+2: aa s 11;
+3: end
+</programlisting>
+ </example>
+
+ <para>This is the message associated to the above sample:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>[ERR 105] Line 2:2 required (...)+ loop did not match anything
+ at input 'aa' in template test_error</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>To fix this problem it is necessary to remove the numeric value
+ as it is neither a valid data type which might begin a new template
+ slot nor a possible start for any other rule file construct.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Other Messages</title>
+
+ <para>If you get any other message, means that something bad happened, so
+ please contact the development team.</para>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Function.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Function.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Function.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <section 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"
+ xmlns:db="http://docbook.org/ns/docbook" xml:base="../../">
+ <title>Function</title>
+
+ <note>
+ <para><replaceable>(updated to Drools 4.0)</replaceable></para>
+ </note>
+
+ <figure>
+ <title>function</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/function.png" format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Functions are a way to put semantic code in your rule source file, as
+ opposed to in normal Java classes. They can't do anything more then what you
+ can do with helper classes (in fact, the compiler generates the helper class
+ for you behind the scenes). The main advantage of using functions in a rule
+ is that you can keep the logic all in one place, and you can change the
+ functions as needed (this can be a good and bad thing). Functions are most
+ useful for invoking actions on the consequence ("then") part of a rule,
+ especially if that particular action is used over and over (perhaps with
+ only differing parameters for each rule - for example the contents of an
+ email message).</para>
+
+ <para>A typical function declaration looks like:</para>
+
+ <programlisting>function String hello(String name) {
+ return "Hello "+name+"!";
+}
+</programlisting>
+
+ <para>Note that the "function" keyword is used, even though its not really
+ part of Java. Parameters to the function are just like a normal method (and
+ you don't have to have parameters if they are not needed). Return type is
+ just like a normal method.</para>
+
+ <para>An alternative to the use of a function, could be to use a static
+ method in a helper class: Foo.hello(). Drools 4.0 supports the use of
+ function imports, so all you would need to do is:</para>
+
+ <programlisting>import function my.package.Foo.hello</programlisting>
+
+ <para>In both cases above, to use the function, just call it by its name in
+ the consequence or inside a semantic code block. Example:</para>
+
+ <programlisting>rule "using a static function"
+when
+ eval( true )
+then
+ System.out.println( hello( "Bob" ) );
+end
+</programlisting>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Keywords.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Keywords.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Keywords.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
+ <note>
+ <para>
+ <replaceable>(updated to Drools 5.0)</replaceable>
+ </para>
+ </note>
+
+ <title>Keywords</title>
+
+ <para>Drools 5 introduces the concept of Hard and Soft keywords.</para>
+
+ <para>Hard keywords are reserved, you cannot use any hard keyword when
+ naming your domain objects, properties, methods, functions and other
+ elements that are used in the rule text.</para>
+
+ <para>Here is a list of hard keywords that must be avoided as identifiers
+ when writing rules:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>true</para>
+ </listitem>
+
+ <listitem>
+ <para>false</para>
+ </listitem>
+
+ <listitem>
+ <para>accumulate</para>
+ </listitem>
+
+ <listitem>
+ <para>collect</para>
+ </listitem>
+
+ <listitem>
+ <para>from</para>
+ </listitem>
+
+ <listitem>
+ <para>null</para>
+ </listitem>
+
+ <listitem>
+ <para>over</para>
+ </listitem>
+
+ <listitem>
+ <para>then</para>
+ </listitem>
+
+ <listitem>
+ <para>when</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Soft keywords are just recognized in their context, enabling you to
+ use this words in any other place you wish. Here is a list of soft
+ keywords:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>lock-on-active</para>
+ </listitem>
+
+ <listitem>
+ <para>date-effective</para>
+ </listitem>
+
+ <listitem>
+ <para>date-expires</para>
+ </listitem>
+
+ <listitem>
+ <para>no-loop</para>
+ </listitem>
+
+ <listitem>
+ <para>auto-focus</para>
+ </listitem>
+
+ <listitem>
+ <para>activation-group</para>
+ </listitem>
+
+ <listitem>
+ <para>agenda-group</para>
+ </listitem>
+
+ <listitem>
+ <para>ruleflow-group</para>
+ </listitem>
+
+ <listitem>
+ <para>entry-point</para>
+ </listitem>
+
+ <listitem>
+ <para>duration</para>
+ </listitem>
+
+ <listitem>
+ <para>package</para>
+ </listitem>
+
+ <listitem>
+ <para>import</para>
+ </listitem>
+
+ <listitem>
+ <para>dialect</para>
+ </listitem>
+
+ <listitem>
+ <para>salience</para>
+ </listitem>
+
+ <listitem>
+ <para>enabled</para>
+ </listitem>
+
+ <listitem>
+ <para>attributes</para>
+ </listitem>
+
+ <listitem>
+ <para>rule</para>
+ </listitem>
+
+ <listitem>
+ <para>extend</para>
+ </listitem>
+
+ <listitem>
+ <para>template</para>
+ </listitem>
+
+ <listitem>
+ <para>query</para>
+ </listitem>
+
+ <listitem>
+ <para>declare</para>
+ </listitem>
+
+ <listitem>
+ <para>function</para>
+ </listitem>
+
+ <listitem>
+ <para>global</para>
+ </listitem>
+
+ <listitem>
+ <para>eval</para>
+ </listitem>
+
+ <listitem>
+ <para>not</para>
+ </listitem>
+
+ <listitem>
+ <para>in</para>
+ </listitem>
+
+ <listitem>
+ <para>or</para>
+ </listitem>
+
+ <listitem>
+ <para>and</para>
+ </listitem>
+
+ <listitem>
+ <para>exists</para>
+ </listitem>
+
+ <listitem>
+ <para>forall</para>
+ </listitem>
+
+ <listitem>
+ <para>action</para>
+ </listitem>
+
+ <listitem>
+ <para>reverse</para>
+ </listitem>
+
+ <listitem>
+ <para>result</para>
+ </listitem>
+
+ <listitem>
+ <para>end</para>
+ </listitem>
+
+ <listitem>
+ <para>init</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Of course, you can have these (hard and soft) words as part of a
+ method name in camel case, like notSomething() or accumulateSomething() -
+ there are no issues with that scenario.</para>
+
+ <para>Another improvement on DRL language is the ability to escape hard
+ keywords on rule text. This new feature enables you to use your existing
+ domain objects without worrying about keyword collision. To escape a word,
+ simple type it between grave accents, like this:</para>
+
+ <programlisting>Holiday( `when` == "july" )</programlisting>
+
+ <para>The escape should be used everywehere in rule text, except within code
+ expressions in the LHS or RHS code block. Here are examples of
+ usage:</para>
+
+ <programlisting>rule "validate holiday by eval"
+dialect "mvel"
+when
+ h1 : Holiday( )
+ eval( h1.when == "july" )
+then
+ System.out.println(h1.name + ":" + h1.when);
+end
+</programlisting>
+
+ <programlisting>rule "validate holiday"
+dialect "mvel"
+when
+ h1 : Holiday( `when` == "july" )
+then
+ System.out.println(h1.name + ":" + h1.when);
+end
+</programlisting>
+</section>
\ No newline at end of file
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Overview.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Overview.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Overview.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
+ <title>Overview</title>
+
+ <note>
+ <para><replaceable>(updated to Drools 4.0)</replaceable></para>
+ </note>
+
+ <para>Drools 4.0 has a "native" rule language that is non XML textual
+ format. This format is very light in terms of punctuation, and supports
+ natural and domain specific languages via "expanders" that allow the
+ language to morph to your problem domain. This chapter is mostly concerted
+ with the native rule format. The Diagrams used are known as "rail road"
+ diagrams, and are basically flow charts for the language terms. For the
+ technically very keen, you can also refer to "DRL.g" which is the Antlr3
+ grammar for the rule language. If you use the Rule Workbench, a lot of the
+ rule structure is done for you with content assistance, for example, type
+ "ru" and press ctrl+space, and it will build the rule structure for
+ you.</para>
+
+ <section>
+ <title>A rule file</title>
+
+ <para>A rule file is typically a file with a .drl extension. In a drl file
+ you can have multiple rules, queries and functions, as well as some
+ resource declarations like imports, globals and attributes that are
+ assigned and used by your rules and queries. However, you are also able to
+ spread your rules across multiple rule files (in that case, the extension
+ .rule is suggested, but not required) - spreading rules across files can
+ help with managing large numbers of rules. A DRL file is simply a text
+ file.</para>
+
+ <para>The overall structure of a rule file is:</para>
+
+ <example>
+ <title>Rules file</title>
+
+ <programlisting><emphasis role="bold">package </emphasis><replaceable>package-name</replaceable>
+
+<replaceable>imports</replaceable>
+
+<replaceable>globals</replaceable>
+
+<replaceable>functions</replaceable>
+
+<replaceable>queries</replaceable>
+
+<replaceable>rules</replaceable>
+</programlisting>
+ </example>
+
+ <para>The order in which the elements are declared is not important,
+ except for the package name that, if declared, must be the first element
+ in the rules file. All elements are optional, so you will use only those
+ you need. We will discuss each of them in the following sections.</para>
+ </section>
+
+ <section>
+ <title>What makes a rule</title>
+
+ <para>For the inpatients, just as an early view, a rule has the following
+ rough structure:<programlisting><emphasis role="bold">rule</emphasis> <replaceable>"name"</replaceable>
+ <replaceable>attributes</replaceable>
+ <emphasis role="bold">when</emphasis>
+ <replaceable>LHS</replaceable>
+ <emphasis role="bold">then</emphasis>
+ <replaceable>RHS</replaceable>
+<emphasis role="bold">end</emphasis>
+</programlisting>It's really that simple. Mostly punctuation is not needed,
+ even the double quotes for "name" are optional, as are newlines.
+ Attributes are simple (always optional) hints to how the rule should
+ behave. LHS is the conditional parts of the rule, which follows a certain
+ syntax which is covered below. RHS is basically a block that allows
+ dialect specific semantic code to be executed.</para>
+
+ <para>It is important to note that white space is not important,
+ <empahsis>except</empahsis> in
+ these case of domain specific languages, in which case each line is
+ processed before the following line (and spaces may be significant to the
+ domain language).</para>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Package.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Package.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Package.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <section 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"
+ xmlns:db="http://docbook.org/ns/docbook" xml:base="../../">
+ <title>Package</title>
+
+ <note>
+ <para><replaceable>(updated to Drools 4.0)</replaceable></para>
+ </note>
+
+ <para>A package is a collection of rules and other related constructs, such
+ as imports and globals. The package members are typically related to each
+ other - perhaps HR rules, for instance. A package represents a namespace,
+ which ideally is kept unique for a given grouping of rules. The package name
+ itself is the namespace, and is not related to files or folders in any
+ way.</para>
+
+ <para>It is possible to assemble rules from multiple rule sources, and have
+ one top level package configuration that all the rules are kept under (when
+ the rules are assembled). Although, it is not possible to merge into the
+ same package resources declared under different names. A single Rulebase,
+ can though, contain multiple packages built on it. A common structure, is to
+ have all the rules for a package in the same file as the package declaration
+ (so that is it entirely self contained).</para>
+
+ <para>The following railroad diagram shows all the components that may make
+ up a package. Note that a package <emphasis>must</emphasis> have a namespace and be declared
+ using standard Java conventions for package names; i.e., no spaces, unlike
+ rule names which allow spaces. In terms of the order of elements, they can
+ appear in any order in the rule file, with the exception of the "package"
+ and "expander" statements being at the top of the file, before any rules
+ appear. In all cases, the semicolons are optional.</para>
+
+ <figure>
+ <title>package</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/package.png" format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <section>
+ <title>import</title>
+
+ <figure>
+ <title>import</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata fileref="images/Chapter-Rule_Language/import.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Import statements work like import statements in Java. You need to
+ specify the fully qualified paths and type names for any objects you want
+ to use in the rules. Drools automatically imports classes from the same
+ named Java package and from the java.lang package.</para>
+ </section>
+
+ <section>
+ <title>expander</title>
+
+ <figure>
+ <title>expander</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata fileref="images/Chapter-Rule_Language/expander.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The expander statement (optional) is used to specify domain specific
+ language (DSL) configurations (which are normally stored in a separate
+ file). This provides clues to the parser how to understand what you are
+ raving on about in your rules. It is important to note that in Drools 4.0
+ (that is different from Drools 3.x) the expander declaration is mandatory
+ for the tools to provide you context assistacnce and to avoid error reporting,
+ but the API allows the program to apply DSL templates, even if the
+ expanders are not declared in the source file.</para>
+ </section>
+
+ <section>
+ <title>global</title>
+
+ <figure>
+ <title>global</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata fileref="images/Chapter-Rule_Language/global.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Globals are global variables. They are used to make application
+ objects available to the rules, and are typically used to provide data or
+ services that the rules use (specially application services used in rule
+ consequences), to return data from the rules (like logs or values added in
+ rules consequence) or for the rules to interact with the application doing
+ callbacks. Globals are not inserted into the Working Memory so they should
+ never be reasoned over; you should use them in rules' LHS only if the global has a
+ constant immutable value. The engine cannot be notified about value
+ changes of globals, and does not track their changes. Incorrect use
+ of globals in constraints may yield
+ surprising results - surprising in a bad way, like when a doctor says
+ "thats interesting" to a chest XRay of yours.</para>
+
+ <para>If multiple packages declare globals with the same identifier they
+ must be of the same type and all of them will reference the same global
+ value.</para>
+
+ <para>In order to use globals you must:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Declare your global variable in your rules file and use it in
+ rules. Example:</para>
+
+ <programlisting>global java.util.List myGlobalList;
+
+rule "Using a global"
+when
+ eval( true )
+then
+ myGlobalList.add( "Hello World" );
+end
+</programlisting>
+ </listitem>
+
+ <listitem>
+ <para>Set the global value on your working memory. It is a best
+ practice to set all global values before asserting any fact to the
+ working memory. Example:</para>
+
+ <programlisting>List list = new ArrayList();
+WorkingMemory wm = rulebase.newStatefulSession();
+wm.setGlobal( "myGlobalList", list );
+</programlisting>
+ </listitem>
+ </orderedlist>
+
+ <para>Note that these are just named instances of objects that you pass in
+ from your application to the working memory. This means you can pass in
+ any object you want: you could pass in a service locator, or perhaps a
+ service itself. With the new 'from' element it is now common to pass a
+ Hibernate session as a global, to allow 'from' to pull data from a named
+ Hibernate query.</para>
+
+ <para>One example may be an instance of a Email service. In your
+ integration code that is calling the rule engine, you get your
+ emailService object, and then set it in the working memory. In the DRL,
+ you declare that you have a global of type EmailService, and give it a
+ name "email". Then in your rule consequences, you can use things like
+ email.sendSMS(number, message).</para>
+
+ <para>Globals are not designed to share data between rules and they should
+ never be used for that purpose. Rules always reason and react to the
+ working memory state, so if you want to "share" data between rules, assert
+ the data to the working memory.</para>
+
+ <para>It is strongly discouraged to set (or change) a global value from
+ inside your rules. We recommend to you always set the value from your
+ application using the working memory interface.</para>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Query.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Query.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Query.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <section 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"
+ xmlns:db="http://docbook.org/ns/docbook" xml:base="../../">
+ <title>Query</title>
+
+ <figure>
+ <title>query</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/query.png" format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>A query contains the structure of the LHS of a rule only (you don't
+ specify "when" or "then"). It is simply a way to query the working memory
+ for facts that match the conditions stated. A query has an optional set of
+ parameters, each of which can also be optionally typed. If type is not
+ given then Object type is assumed. The engine will attempt to co-erce
+ the values as needed. Query names are global to the RuleBase, so do
+ not add queries of the same name to different packages for the same Rule
+ Base.</para>
+
+ <para>To return the results use WorkingMemory.getQueryResults("name"),
+ where "name" is the query's name. This returns a list of query results,
+ which allow you to to get to the objects that matched the query.</para>
+
+ <para>The first example creates a simple query for all the people over
+ the age of 30. The second one, using parameters, combines the age limit
+ with a location.</para>
+
+ <example>
+ <title>Query People over the age of 30</title>
+
+ <programlisting>query "people over the age of 30"
+ person : Person( age > 30 )
+end</programlisting>
+ </example>
+
+ <example>
+ <title>Query People over the age of x, and who live in y</title>
+
+ <programlisting>query "people over the age of x" (int x, String y)
+ person : Person( age > x, location == y )
+end</programlisting>
+ </example>
+
+ <para>We iterate over the returned QueryResults using a standard 'for' loop.
+ Each element returns a QueryResult which we can use to access each of the
+ columns in the Tuple. Those columns can be accessed by bound declaration name
+ or index position.</para>
+
+ <example>
+ <title>Query People over the age of 30</title>
+
+ <programlisting>QueryResults results = workingMemory.getQueryResults( "people over the age of 30" );
+System.out.println( "we have " + results.size() + " people over the age of 30" );
+
+System.out.println( "These people are are over 30:" );
+
+for ( Iterator it = results.iterator; it.hasNext(); ) {
+ QueryResult result = ( QueryResult ) it.next();
+ Person person = ( Person ) result.get( "person" );
+ System.out.println( person.getName() + "\n" );
+}</programlisting>
+ </example>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Rule.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Rule.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-Rule.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,2145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <section 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"
+ xmlns:db="http://docbook.org/ns/docbook" xml:base="../../">
+ <title>Rule</title>
+
+ <figure>
+ <title>rule</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/rule.png" format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>A rule specifies that "when" a particular set of conditions occur,
+ specified in the Left Hand Side (LHS), then do this, which is specified as a
+ list of actions in the Right Hand Side (RHS). A common question from users
+ is "why use when instead of if". "when" was chosen over "if" because "if" is
+ normally part of a procedural execution flow, where at a specific point in
+ time it checks the condition. Where as "when" indicates it's not tied to a
+ specific evaluation sequence or point in time, at any time during the life
+ time of the engine "when" this occurs, do that Rule.</para>
+
+ <para>A rule must have a name, unique within its rule package. If
+ you define a rule twice in the same DRL it produces an error while loading.
+ If you add a DRL that includes a rule name already in the package, it
+ replaces the previous rule. If a rule name is to have spaces, then it
+ will need to be enclosd in double quotes (it is best to always use double
+ quotes).</para>
+
+ <para>Attributes are optional, and are described below (they are best kept
+ as one per line).</para>
+
+ <para>The LHS of the rule follows the "when" keyword (ideally on a new
+ line), similarly the RHS follows the "then" keyword (ideally on a newline).
+ The rule is terminated by the keyword "end". Rules cannot be nested of
+ course.</para>
+
+ <example>
+ <title>Rule Syntax Overview Example</title>
+
+ <programlisting>rule "<name>"
+ <attribute>*
+when
+ <conditional element>*
+then
+ <action>*
+end</programlisting>
+ </example>
+
+ <example>
+ <title>A rule example</title>
+
+ <programlisting>rule "Approve if not rejected"
+ salience -100
+ agenda-group "approval"
+ when
+ not Rejection()
+ p : Policy(approved == false, policyState:status)
+ exists Driver(age > 25)
+ Process(status == policyState)
+ then
+ log("APPROVED: due to no objections.");
+ p.setApproved(true);
+end</programlisting>
+ </example>
+
+ <section>
+ <title>Rule Attributes</title>
+
+ <para>Rule attributes provide a declarative way to influence the behavior
+ of the rule. Some are quite simple, while others are part of complex sub
+ systems such as ruleflow. To get the most from Drools you should make
+ sure you have a proper understanding of each attribute.</para>
+
+ <figure>
+ <title>rule attributes</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/rule_attributes.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <variablelist>
+ <varlistentry>
+ <term>no-loop</term>
+
+ <listitem>
+ <para>default value: false</para>
+
+ <para>type: Boolean</para>
+
+ <para>When the Rule's consequence modifies a fact it may cause
+ the Rule to activate again, causing recursion. Setting no-loop
+ to true means the attempt to create the Activation for the
+ current set of data will be ignored.</para>
+ </listitem>
+
+ </varlistentry>
+
+ <varlistentry>
+ <term>lock-on-active</term>
+
+ <listitem>
+ <para>default value: false</para>
+
+ <para>type: Boolean</para>
+ <para>Whenever a ruleflow-group becomes active or an
+ agenda-group receives the focus, any rule within that
+ group that has lock-on-active set to true will not be
+ activated any more; irrespective of the origin of the
+ update, the activation of a matching rule is discarded.
+ This is a stronger version of no-loop, because the change
+ could now be caused not only by the rule itself. It's
+ ideal for calculation rules where you have a number of
+ rules that modify a fact and you don't want any rule
+ re-matching and firing again. Only when the ruleflow-group
+ is no longer active or the agenda-group loses the focus
+ those rules with lock-on-active set to true become
+ eligible again for their activations to be placed onto
+ the agenda.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>salience</term>
+
+ <listitem>
+ <para>default value : 0</para>
+
+ <para>type : integer</para>
+
+ <para>Each rule has a salience attribute that can be assigned
+ an Integer number, defaults to zero, the Integer and can be
+ negative or positive. Salience is a form of priority where
+ rules with higher salience values are given higher priority
+ when ordered in the Activation queue.</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>agenda-group</term>
+
+ <listitem>
+ <para>default value: MAIN</para>
+
+ <para>type: String</para>
+
+ <para>Agenda group's allow the user to partition the Agenda providing more execution control. Only rules in the focus group are allowed to fire.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>auto-focus</term>
+
+ <listitem>
+ <para>default value: false</para>
+
+ <para>type: Boolean</para>
+
+ <para>When a rule is activated if the <literal>auto-focus value is true and the Rule's </literal> <literal>agenda-group</literal> does not have focus then it is given focus, allowing the rule to potentially fire.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>activation-group</term>
+
+ <listitem>
+ <para>default value: N/A</para>
+
+ <para>type: String</para>
+
+ <para>Rules that belong to the same named activation-group will only fire exclusively. In other words, the first rule in an activation-group to fire will cancel the other rules activations (stop them from firing). The Activation group attribute is any string, as long as the string is identical for all the rules you need to be in the one group.</para>
+
+ <para>NOTE: this used to be called Xor group, but technically its not quite an Xor, but you may hear people mention Xor group, just swap that term in your mind with activation-group.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>dialect</term>
+
+ <listitem>
+ <para>default value : as specified by the package</para>
+
+ <para>type : String</para>
+
+ <para>possible values: "java" or "mvel"</para>
+
+ <para>The dialect species the language to be used for any code
+ expressions in the LHS or the RHS code block. Currently two dialects are available, Java and MVEL. While the dialect can be specified at the package level, this attribute allows the package definition to be overridden.</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>date-effective</term>
+
+ <listitem>
+ <para>default value: N/A</para>
+
+ <para>type: String, which contains a date and time definition</para>
+
+ <para>A rule can only activate if the current date and time is after date-effective attribute.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>date-expires</term>
+
+ <listitem>
+ <para>default value: N/A</para>
+
+ <para>type: String, which contains a date and time definition</para>
+
+ <para>A rule cannot activate if the current date and time is after date-expires attribute.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>duration</term>
+
+ <listitem>
+ <para>default value: no default value</para>
+
+ <para>type: long</para>
+
+ <para>The duration dictates that the rule will fire after a specified duration, if it is still true.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <example>
+ <title>Some attribute examples</title>
+
+ <programlisting>rule "my rule"
+ salience 42
+ agenda-group "number 1"
+ when ...
+</programlisting>
+ </example>
+ </section>
+
+ <section id="RuleLanguage-ConditionalElements">
+ <title>Left Hand Side (when) Conditional Elements</title>
+
+ <para>The Left Hand Side (LHS) is a common name for the conditional part
+ of the rule. It consists of zero or more Conditional Elements. If the LHS
+ is left empty it is re-written as eval(true), which means the rule is
+ always true, and will be activated when a new Working Memory session is
+ created.</para>
+
+ <figure>
+ <title>Left Hand Side</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/lhs.png" format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <example>
+ <title>Rule without a Conditional Element</title>
+
+ <programlisting>rule "no CEs"
+when
+then
+ <action>*
+end</programlisting>
+
+ <para>Is internally re-written as:</para>
+
+ <programlisting>rule "no CEs"
+when
+ eval( true )
+then
+ <action>*
+end</programlisting>
+ </example>
+
+ <para>Conditional elements work on one or more <emphasis>patterns</emphasis> (which are
+ described below). The most common one is "and" which is implicit when you
+ have multiple patterns in the LHS of a rule that are not connected in
+ any way. Note that an 'and' cannot have a leading declaration binding like
+ 'or'. This is obvious, since a declaration can only
+ reference a single fact, and when the 'and' is satisfied it matches more than
+ one fact - which fact would the declaration bind to?</para>
+
+ <section>
+ <title>Pattern</title>
+
+ <para>The pattern element is the most important Conditional Element. The
+ entity relationship diagram below provides an overview of the various
+ parts that make up the pattern's constraints and how they work together;
+ each is then covered in more detail with railroad diagrams and
+ examples.</para>
+
+ <figure>
+ <title>Pattern Entity Relationship Diagram</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/patternER.png" format="PNG"
+ role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>At the top of the ER diagram you can see that the pattern consists
+ of zero or more constraints and has an optional pattern binding. The
+ railroad diagram below shows the syntax for this.</para>
+
+ <figure>
+ <title>Pattern</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/pattern.png" format="PNG"
+ role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>In its simplest form, with no constraints, it simply matches against a
+ type. In the following case the type is "Cheese", which means that the pattern
+ will match against all Cheese objects in the Working Memory.</para>
+
+ <example>
+ <title>Simple Pattern</title>
+
+ <programlisting>Cheese( )</programlisting>
+ </example>
+
+ <para>To be able to refer to the matched object use a pattern binding
+ variable such as '$c'. While this example variable is prefixed with a $
+ symbol, it is optional, but can be useful in complex rules as it helps
+ to more easily differentiation between variables and fields.</para>
+
+ <example>
+ <title>Pattern with a binding variable</title>
+
+ <programlisting>$c : Cheese( )</programlisting>
+ </example>
+
+ <para>Inside of the pattern parenthesis is where all the action happens.
+ A constraint can be either a Field Constraint, Inline Eval (called a
+ predicate in 3.0) or a Constraint Group. Constraints can be separated by
+ the following symbols: ',', '&&' or '||'.</para>
+
+ <figure>
+ <title>Constraints</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/constraints.png" format="PNG"
+ role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <figure>
+ <title>Constraint</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/constraint.png" format="PNG"
+ role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <figure>
+ <title>Group Constraint</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/constraintGroup.png"
+ format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The ',' (comma) character is used to separate constraint groups.
+ It has implicit 'and' connective semantics.<example>
+ <title>Constraint Group connective ','</title>
+
+ <programlisting># Cheese type is stilton and price < 10 and age is mature.
+Cheese( type == "stilton", price < 10, age == "mature" )</programlisting>
+ </example>The above example has 3 constraint groups, each with a
+ single constraint:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>group 1: type is stilton -> type == "stilton"</para>
+ </listitem>
+
+ <listitem>
+ <para>group 2: price is less than 10 -> price < 10</para>
+ </listitem>
+
+ <listitem>
+ <para>group 3: age is mature -> age == "mature"</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The '&&' (and) and '||' (or) constraint connectives allow
+ constraint groups to have multiple constraints. Example:</para>
+
+ <example>
+ <title>&& and || Constraint Connectives</title>
+
+ <programlisting>Cheese( type == "stilton" && price < 10, age == "mature" ) // Cheese type is "stilton" and price < 10, and age is mature
+Cheese( type == "stilton" || price < 10, age == "mature" ) // Cheese type is "stilton" or price < 10, and age is mature</programlisting>
+ </example>
+
+ <para>The above example has two constraint groups. The first has 2
+ constraints and the second has one constraint.</para>
+
+ <para>The connectives are evaluated in the following order, from first
+ to last:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>&&</para>
+ </listitem>
+
+ <listitem>
+ <para>||</para>
+ </listitem>
+
+ <listitem>
+ <para>,</para>
+ </listitem>
+ </orderedlist>
+
+ <para>It is possible to change the evaluation priority by using
+ parenthesis, as in any logic or mathematical expression. Example:</para>
+
+ <para><example>
+ <title>Using parenthesis to change evaluation priority</title>
+
+ <programlisting># Cheese type is stilton and ( price is less than 20 or age is mature ).
+Cheese( type == "stilton" && ( price < 20 || age == "mature" ) ) </programlisting>
+ </example>In the above example, the use of parenthesis makes the ||
+ connective be evaluated before the && connective.</para>
+
+ <para>Also, it is important to note that besides having the same
+ semantics, the connectives '&&' and ',' are resolved with
+ different priorities and ',' cannot be embedded in a composite
+ constraint expression.</para>
+
+ <example>
+ <title>Not Equivalent connectives</title>
+
+ <programlisting>Cheese( ( type == "stilton", price < 10 ) || age == "mature" ) // invalid as ',' cannot be embedded in an expression
+Cheese( ( type == "stilton" && price < 10 ) || age == "mature") // valid as '&&' can be embedded in an expression</programlisting>
+ </example>
+
+ <section>
+ <title>Field Constraints</title>
+
+ <para>A Field constraint specifies a restriction to be used on a field
+ name; the field name can have an optional variable binding.</para>
+
+ <figure>
+ <title>fieldConstraint</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/fieldConstraint.png"
+ format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>There are three types of restrictions; Single Value Restriction,
+ Compound Value Restriction and Multi Restriction.</para>
+
+ <figure>
+ <title>restriction</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/restriction.png" format="PNG"
+ role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <section>
+ <title>JavaBeans as facts</title>
+
+ <para>A field is an accessible method on the object. If your model
+ objects follow the Java bean pattern, then fields are exposed using
+ "getXXX" or "isXXX" methods (these are methods that take no
+ arguments, and return something). You can access fields either by
+ using the bean naming convention (so "getType" can be accessed as
+ "type") - we use the standard jdk Introspector class to do this
+ mapping.</para>
+
+ <para>For example, referring to our Cheese class, the pattern
+ Cheese(type == ...) applies the getType() method to a Cheese
+ instance. If a field name cannot be found it will resort to calling
+ the name as a no argument method; "toString()" on the Object for
+ instance can be used with Cheese(toString == ..) - you use the full
+ name of the method with correct capitalization, but without parentheses. Do
+ please make sure that you are accessing methods that take no
+ parameters, and are in-fact "accessors" which don't change
+ the state of the object in a way that may effect the rules.
+ Remember that the rule engine effectively caches the results of its
+ matching in between invocations to make it faster.</para>
+ </section>
+
+ <section>
+ <title>Values</title>
+
+ <para>The field constraints can take a number of values; including
+ literal, qualifiedIdentifier (enum), variable and
+ returnValue.</para>
+
+ <figure>
+ <title>literal</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/literal.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <figure>
+ <title>qualifiedIdentifier</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/qualifiedIdentifier.png"
+ format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <figure>
+ <title>variable</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/identifier.png"
+ format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <figure>
+ <title>returnValue</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/returnValue.png"
+ format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>You can do checks against fields that are or may be null, using
+ == and != as you would expect, and the literal "null" keyword, like:
+ Cheese(type != null). If a field is null the evaluator will not
+ throw an exception and will only return true if the value is null.
+ Coercion is always attempted if the field and the value are
+ of different types; exceptions will be thrown if bad coercions are
+ attempted. For instance, if "ten" is provided as a string in a number
+ evaluator an exception is thrown, whereas "10" would coerce to a
+ numeric 10. Coercion is
+ always in favor of the field type and not the value type.</para>
+ </section>
+
+ <section>
+ <title>Single Value Restriction</title>
+
+ <figure>
+ <title>singleValueRestriction</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/singleValueRestriction.png"
+ format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <section>
+ <title>Operators</title>
+
+ <figure>
+ <title>Operators</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/operator.png"
+ format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Valid operators are dependent on the field type. Generally
+ they are self explanatory based on the type of data: for instance,
+ for date fields, "<" means "before". "Matches" is
+ only applicable to string fields, "contains" and "not contains" is
+ only applicable to Collection type fields. These operators can be
+ used with any value and coercion to the correct value for the
+ evaluator and field will be attempted, as mentioned in the "Values"
+ section.</para>
+
+ <simplesect>
+ <title>Matches Operator</title>
+
+ <para>Matches a field against any valid Java <indexterm>
+ <primary>regular expression</primary>
+ </indexterm>Regular Expression. Typically that regexp is a
+ String, but variables that resolve to a valid regexp are also
+ allowed. It is important to note that, <emphasis>different from
+ Java</emphasis>, if you write a String regexp directly on the
+ source file, <emphasis>you don't need to escape '\'</emphasis>.
+ Example:</para>
+
+ <example>
+ <title>Regular Expression Constraint</title>
+
+ <programlisting>Cheese( type matches "(Buffalo)?\S*Mozerella" )</programlisting>
+ </example>
+ </simplesect>
+
+ <simplesect>
+ <title>Not Matches Operator</title>
+
+ <para>Any valid Java <indexterm>
+ <primary>regular expression</primary>
+ </indexterm>Regular Expression can be used to match String
+ fields. This operator returns true when the match is false. Typically that
+ regexp is a String, but variables that resolve to a valid regexp
+ are also allowed. It is important to note that,
+ <emphasis>different from Java</emphasis>, if you write a String
+ regexp directly on the source file, <emphasis>you don't need to
+ escape '\'</emphasis>. Example:</para>
+
+ <example>
+ <title>Regular Expression Constraint</title>
+
+ <programlisting>Cheese( type not matches "(Buffulo)?\S*Mozerella" )</programlisting>
+ </example>
+ </simplesect>
+
+ <simplesect>
+ <title>Contains Operator</title>
+
+ <para><literal>'contains'</literal> is used to check if a
+ field's <indexterm>
+ <primary>Collection</primary>
+ </indexterm>Collection or array contains the specified
+ value.</para>
+
+ <example>
+ <title>Contains with Collections</title>
+
+ <programlisting>CheeseCounter( cheeses contains "stilton" ) // contains with a String literal
+CheeseCounter( cheeses contains $var ) // contains with a variable</programlisting>
+ </example>
+ </simplesect>
+
+ <simplesect>
+ <title>not contains</title>
+
+ <para><literal>'not contains'</literal> is used to check if a
+ field's <indexterm>
+ <primary>Collection</primary>
+ </indexterm>Collection or array does not contain an
+ object.</para>
+
+ <example>
+ <title>Literal Constraints with Collections</title>
+
+ <programlisting>CheeseCounter( cheeses not contains "cheddar" ) // not contains with a String literal
+CheeseCounter( cheeses not contains $var ) // not contains with a variable</programlisting>
+ </example>
+
+ <blockquote>
+ <para><emphasis role="bold">NOTE: </emphasis>for backward
+ compatibility, the '<emphasis
+ role="bold">excludes</emphasis>' operator is supported as a
+ synonym for '<emphasis role="bold">not
+ contains</emphasis>'.</para>
+ </blockquote>
+ </simplesect>
+
+ <simplesect>
+ <title>memberOf</title>
+
+ <para><literal>'memberOf'</literal> is used to check if a field is a
+ member of a collection or array; that collection must be be a
+ variable.</para>
+
+ <example>
+ <title>Literal Constraints with Collections</title>
+
+ <programlisting>CheeseCounter( cheese memberOf $matureCheeses )</programlisting>
+ </example>
+ </simplesect>
+
+ <simplesect>
+ <title>not memberOf</title>
+
+ <para><literal>'not memberOf'</literal> is used to check if a field is not
+ a member of a collection or array; that collection must be be a
+ variable.</para>
+
+ <example>
+ <title>Literal Constraints with Collections</title>
+
+ <programlisting>CheeseCounter( cheese not memberOf $matureCheeses )</programlisting>
+ </example>
+ </simplesect>
+
+ <simplesect>
+ <title>soundslike</title>
+
+ <para>Similar to <literal>'matches'</literal>, but checks if a word has
+ almost the same sound as the given value. Uses the 'Soundex'
+ algorithm
+ (<literal>http://en.wikipedia.org/wiki/Soundex</literal>).</para>
+
+ <example>
+ <title>Text with soundslike (Sounds Like)</title>
+
+ <programlisting>Cheese( name soundslike 'foobar' )</programlisting>
+ </example>
+ <para>This will match a cheese with a name of "fubar"</para>
+ </simplesect>
+ </section>
+
+ <section>
+ <title>Literal Restrictions</title>
+
+ <para>Literal restrictions are the simplest form of restrictions
+ and evaluate a field against a specified literal; numeric, date,
+ string or boolean.</para>
+
+ <figure>
+ <title>literalRestriction</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/literalRestriction.png"
+ format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Literal Restrictions using the '==' operator, provide for
+ faster execution as we can index using hashing to improve
+ performance.</para>
+
+ <simplesect>
+ <title>Numeric</title>
+
+ <para>All standard Java numeric primitives are supported.</para>
+
+ <example>
+ <title>Numeric Literal Restriction</title>
+
+ <programlisting>Cheese( quantity == 5 )</programlisting>
+ </example>
+ </simplesect>
+
+ <simplesect>
+ <title>Date</title>
+
+ <para>The date format "dd-mmm-yyyy" is supported by default. You
+ can customize this by providing an alternative date format mask
+ as a System property ("drools.dateformat" is the name of the
+ property). If more control is required, use the inline-eval
+ constraint.</para>
+
+ <example>
+ <title>Date Literal Restriction</title>
+
+ <programlisting>Cheese( bestBefore < "27-Oct-2007" )</programlisting>
+ </example>
+ </simplesect>
+
+ <simplesect>
+ <title>String</title>
+
+ <para>Any valid Java String is allowed.</para>
+
+ <example>
+ <title>String Literal Restriction</title>
+
+ <programlisting>Cheese( type == "stilton" )</programlisting>
+ </example>
+ </simplesect>
+
+ <simplesect>
+ <title>Boolean</title>
+
+ <para>Only true or false can be used; 0 and 1 are not
+ recognized. A Boolean field alone (as in
+ <code>Cheese( smelly )</code> is not permitted.</para>
+
+ <example>
+ <title>Boolean Literal Restriction</title>
+
+ <programlisting>Cheese( smelly == true )</programlisting>
+ </example>
+ </simplesect>
+
+ <simplesect>
+ <title>Qualified Identifier</title>
+
+ <para>Enums can be used as well, both jdk1.4 and jdk5 style
+ enums are supported. For the latter you must be executing on a
+ jdk5 environment.</para>
+
+ <example>
+ <title>Boolean Literal Restriction</title>
+
+ <programlisting>Cheese( smelly == SomeClass.TRUE )</programlisting>
+ </example>
+ </simplesect>
+ </section>
+
+ <section>
+ <title>Bound Variable Restriction</title>
+
+ <figure>
+ <title>variableRestriction</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/variableRestriction.png"
+ format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Variables can be bound to Facts and their Fields and then
+ used in subsequent Field Constraints. A bound variable is called a
+ <indexterm>
+ <primary>declaration</primary>
+ </indexterm>Declaration. Valid operators are determined by the
+ type of the field being constrained; coercion will be attempted
+ where possible. Bound Variable Restrictions using '==' operator,
+ provide for very fast execution as we can index using hashing to
+ improve performance.</para>
+
+ <example>
+ <title>Bound Field using '==' operator</title>
+
+ <programlisting>Person( likes : favouriteCheese )
+Cheese( type == likes )</programlisting>
+
+ <para>'likes' is our variable, our Declaration, that is bound to
+ the favouriteCheese field for any matching Person instance and
+ is used to constrain the type of Cheese in the following
+ pattern. Any valid Java variable name can be used, and it may
+ be prefixed with a '$', which you will often see used to help differentiate
+ declarations from fields. The example below shows a declaration
+ bound to the pattern's Object Type instance itself and used with
+ a 'contains' operator. Note the optional use of '$'.</para>
+ </example>
+
+ <example>
+ <title>Bound Fact using 'contains' operator</title>
+
+ <programlisting>$stilton : Cheese( type == "stilton" )
+Cheesery( cheeses contains $stilton )</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>Return Value Restriction</title>
+
+ <figure>
+ <title>returnValueRestriction</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Language/returnValueRestriction.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>A <indexterm>
+ <primary>Return Value</primary>
+ </indexterm>Return Value restriction can use any valid Java
+ primitive or object. Avoid using any Drools keywords as
+ Declaration identifiers. Functions used in a Return Value
+ Restriction must return time constant results. Previously bound
+ declarations can be used in the expression.</para>
+
+ <example>
+ <title>Return Value Restriction</title>
+
+ <programlisting>Person( girlAge : age, sex == "F" )
+Person( age == ( girlAge + 2) ), sex == 'M' )
+</programlisting>
+ </example>
+ </section>
+ </section>
+
+ <section>
+ <title>Compound Value Restriction</title>
+
+ <para>The compound value restriction is used where there is more
+ than one possible value, currently only the 'in' and 'not in'
+ evaluators support this. The operator takes a parenthesis enclosed
+ comma separated list of values, which can be a variable, literal,
+ return value or qualified identifier. The 'in' and 'not in'
+ evaluators are actually sugar and are rewritten as a multi
+ restriction list of != and == restrictions.</para>
+
+ <figure>
+ <title>compoundValueRestriction</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Language/compoundValueRestriction.png" format="PNG"
+ role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para></para>
+
+ <example>
+ <title>Compound Restriction using 'in'</title>
+
+ <programlisting>Person( $cheese : favouriteCheese )
+Cheese( type in ( "stilton", "cheddar", $cheese )
+</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>Multi Restriction</title>
+
+ <para>Multi restriction allows you to place more than one
+ restriction on a field using the '&&' or '||' restriction
+ connectives. Grouping via parenthesis is also allowed; which adds a
+ recursive nature to this restriction.</para>
+
+ <figure>
+ <title>multiRestriction</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/multiRestriction.png"
+ format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <figure>
+ <title>restrictionGroup</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/restrictionGroup.png"
+ format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para></para>
+
+ <example>
+ <title>Multi Restriction</title>
+
+ <programlisting>Person( age > 30 && < 40 ) // simple multi restriction using a single &&
+Person( age ( (> 30 && < 40) || (> 20 && < 25) ) ) // more complex multi restriction using groupings of multi restrictions
+Person( age > 30 && < 40 || location == "london" ) // mixing muti restrictions with constraint connectives</programlisting>
+ </example>
+ </section>
+ </section>
+
+ <section>
+ <title>Inline Eval Constraints</title>
+
+ <figure>
+ <title>Inline Eval Expression</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/inlineEvalConstraint.png"
+ format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>An <indexterm>
+ <primary>Predicate</primary>
+ </indexterm>inline-eval constraint can use any valid dialect
+ expression as long as it is evaluated to a primitive boolean - avoid
+ using any Drools keywords as Declaration identifiers. The expression
+ must be time constant. Any previously bound variable, from the current
+ or previous pattern, can be used; autovivification is also used to
+ auto-create field binding variables. When an identifier is found that
+ is not a current variable the builder looks to see if the identifier
+ is a field on the current object type, if it is, the field binding
+ is auto-created as a variable of the same name. This is called
+ autovivification of field variables inside of inline evals.</para>
+
+ <para>This example will find all male-female pairs where the
+ male is 2 years older than the female; the boyAge variable is
+ auto-created by the autovivification process.</para>
+
+ <example>
+ <title>Return Value operator</title>
+
+ <programlisting>Person( girlAge : age, sex = "F" )
+Person( eval( age == girlAge + 2 ), sex = 'M' )
+</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>Nested Accessors</title>
+
+ <para>Drools does allow for nested accessors in in the field
+ constraints using the MVEL accessor graph notation. Field constraints
+ involving nested accessors are actually re-written as an MVEL dialect
+ inline-eval. Care should be taken when using nested accessors as the
+ Working Memory is not aware of any of the nested values, and do not
+ know when they change; they should be considered immutable while any
+ of their parent references are inserted into the Working Memory. If
+ you wish to modify a nested value you should remove the parent objects
+ first and re-assert afterwards. If you only have a single parent at
+ the root of the graph, when in the MVEL dialect, you can use the
+ 'modify' keyword and its block setters to write the nested accessor
+ assignments while retracting and inserting the the root parent object
+ as required. Nested accessors can be used either side of the operator
+ symbol.</para>
+
+ <example>
+ <title>Nested Accessors</title>
+
+ <programlisting>$p : Person( )
+Pet( owner == $p, age > $p.children[0].age ) // Find a pet who is older than their owners first born child</programlisting>
+
+ <para>is internally rewriten as an MVEL inline eval:</para>
+
+ <programlisting>$p : Person( )
+Pet( owner == $p, eval( age > $p.children[0].age ) ) // Find a pet who is older than their owners first born child</programlisting>
+ </example>
+
+ <remark>NOTE: nested accessors have a much greater performance cost
+ than direct field access, so use them carefully.</remark>
+ </section>
+ </section>
+
+ <section>
+ <title>'and'</title>
+
+ <para>The 'and' Conditional Element is used to group together other
+ Conditional Elements. The root element of the LHS is an implicit prefix
+ And and doesn't need to be specified. Drools supports both prefix and
+ infix; although prefix is the preferred option as grouping is implicit
+ which avoids confusion.</para>
+
+ <figure>
+ <title>prefixAnd</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/prefixAnd.png" format="PNG"
+ role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para></para>
+
+ <example>
+ <title>prefixAnd</title>
+
+ <programlisting>(and Cheese( cheeseType : type )
+ Person( favouriteCheese == cheeseType ) )
+</programlisting>
+ </example>
+
+ <example>
+ <title>implicit root prefixAnd</title>
+
+ <programlisting>when
+ Cheese( cheeseType : type )
+ Person( favouriteCheese == cheeseType )</programlisting>
+ </example>
+
+ <para>Infix 'and' is supported along with explicit grouping with
+ parenthesis, should it be needed. The '&&' symbol, as an
+ alternative to 'and', is deprecated although it is still supported in
+ the syntax for legacy support reasons.</para>
+
+ <figure>
+ <title>infixAnd</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/infixAnd.png" format="PNG"
+ role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <example>
+ <title>infixAnd</title>
+
+ <programlisting>Cheese( cheeseType : type ) and Person( favouriteCheese == cheeseType ) //infixAnd
+(Cheese( cheeseType : type ) and (Person( favouriteCheese == cheeseType ) or Person( favouriteCheese == cheeseType ) ) //infixAnd with grouping</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>'or'</title>
+
+ <para>The 'or' Conditional Element is used to group together other
+ Conditional Elements. Drools supports both prefix and infix; although
+ prefix is the preferred option as grouping is implicit which avoids
+ confusion. The behavior of the 'or' Conditional Element is different
+ than the '||' connective for constraints and restrictions in field
+ constraints. The engine actually has no understanding of 'or'
+ Conditional Elements, instead via a number of different logic
+ transformations the rule is re-written as a number of subrules; the rule
+ now has a single 'or' as the root node and a subrule per logical
+ outcome. Each subrule can activate and fire like any normal rule, there
+ is no special behavior or interactions between the subrules - this can
+ be most confusing to new rule authors.</para>
+
+ <figure>
+ <title>prefixOr</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/prefixOr.png" format="PNG"
+ role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <example>
+ <title>prefixOr</title>
+
+ <programlisting>(or Person( sex == "f", age > 60 )
+ Person( sex == "m", age > 65 )
+</programlisting>
+ </example>
+
+ <para>Infix 'or' is supported along with explicit grouping with
+ parenthesis, should it be needed. The '||' symbol, as an alternative to
+ 'or', is deprecated although it is still supported in the syntax for
+ legacy support reasons.</para>
+
+ <figure>
+ <title>infixOr</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/infixOr.png" format="PNG"
+ role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <example>
+ <title>infixOr</title>
+
+ <programlisting>Cheese( cheeseType : type ) or Person( favouriteCheese == cheeseType ) //infixOr
+(Cheese( cheeseType : type ) or (Person( favouriteCheese == cheeseType ) and Person( favouriteCheese == cheeseType ) ) //infixOr with grouping</programlisting>
+ </example>
+
+ <para>The 'or' Conditional Element also allows for optional pattern
+ binding; which means each resulting subrule will bind its pattern to
+ the pattern binding. Each pattern must be bound separately,
+ using eponymous variables:</para>
+
+ <example>
+ <title>or with binding</title>
+
+ <programlisting>(or pensioner : Person( sex == "f", age > 60 )
+ pensioner : Person( sex == "m", age > 65 ) )</programlisting>
+ </example>
+
+ <para>The 'or' conditional element results in multiple rule generation,
+ called sub rules, for each possible logically outcome. The example above
+ would result in the internal generation of two rules. These two rules
+ work independently within the Working Memory, which means both can
+ match, activate and fire - there is no shortcutting.</para>
+
+ <para>The best way to think of the OR conditional element is as a
+ shortcut for generating two or more similar rules. When you think
+ of it that
+ way, it's clear that for a single rule there could be multiple
+ activations if both sides of the OR conditional element are true.</para>
+ </section>
+
+ <section>
+ <title>'eval'</title>
+
+ <figure>
+ <title>eval</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/eval.png" format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Eval is essentially a catch all which allows any semantic code
+ (that returns a primitive boolean) to be executed. This can refer to
+ variables that were bound in the LHS of the rule, and functions in the
+ rule package. Overuse of eval reduces the declarative-ness of your rules
+ and can result in a poor performing engine. While 'evals' can be used
+ anywhere in the Pattern the best practice is to add it as the last
+ conditional element in the LHS of a rule.</para>
+
+ <para>Evals cannot be indexed and thus are not as optimal as using Field
+ Constraints. However this makes them ideal for being used when functions
+ return values that change over time, which is not allowed within Field
+ Constraints.</para>
+
+ <para>For folks who are familiar with Drools 2.x lineage, the old Drools
+ parameter and condition tags are equivalent to binding a variable to an
+ appropriate type, and then using it in an eval node.</para>
+
+ <example>
+ <title>eval</title>
+
+ <programlisting>p1 : Parameter()
+p2 : Parameter()
+eval( p1.getList().containsKey(p2.getItem()) )
+eval( isValid(p1, p2) ) //this is how you call a function in the LHS - a function called "isValid"</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>'not'</title>
+
+ <figure>
+ <title>not</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/not.png" format="PNG" role="" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>'not' is first order logic's Non-Existential Quantifier and checks
+ for the non existence of something in the Working Memory. Think of 'not'
+ as meaning "there must be none of...".</para>
+
+ <para>A 'not' statement must be followed by parentheses around the CEs
+ that it applies to. In the simplest case of a single pattern (like
+ below) you may optionally omit the parentheses.</para>
+
+ <example>
+ <title>No Busses</title>
+
+ <programlisting>not Bus()</programlisting>
+ </example>
+
+ <example>
+ <title>No red Busses</title>
+
+ <programlisting>not Bus(color == "red") //brackets are optional for this simple pattern
+not ( Bus(color == "red", number == 42) ) //brackets are optional for this simple case
+not ( Bus(color == "red") and Bus(color == "blue")) // not with nested 'and' infix used here as only two patterns
+ (but brackets are required).</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>'exists'</title>
+
+ <figure>
+ <title>exists</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/exists.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>'exists' is first order logic's Existential Quantifier and checks
+ for the existence of something in the Working Memory. Think of exist as
+ meaning "at least one..". It is different from just having the Pattern
+ on its own; which is more like saying "for each one of...". If you use
+ exist with a Pattern, then the rule will only activate at most once,
+ regardless
+ of how much data there is in working memory that matches that
+ condition. Since only the existence matters, no bindings will be
+ established.</para>
+
+ <para>An 'exist' statement must be followed by parentheses around the
+ CEs that it applies to. In the simplest case of a single pattern (like
+ below) you may optionally omit the parentheses.</para>
+
+ <example>
+ <title>Atleast one Bus</title>
+
+ <programlisting>exists Bus()</programlisting>
+ </example>
+
+ <example>
+ <title>At least one red Bus</title>
+
+ <programlisting>exists Bus(color == "red")
+exists ( Bus(color == "red", number == 42) ) //brackets are optional
+exists ( Bus(color == "red") and Bus(color == "blue")) // exists with nested 'and' infix used here as ony two patterns</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>'forall'</title>
+
+ <figure>
+ <title>forall</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/forall.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The <emphasis role="bold">forall</emphasis> Conditional Element
+ completes the First Order Logic support in Drools. The <emphasis
+ role="bold">forall</emphasis> Conditional Element will evaluate to true
+ when all facts that match the first pattern match all the remaining
+ patterns. Example:</para>
+
+ <programlisting>rule "All english buses are red"
+when
+ forall( $bus : Bus( type == 'english')
+ Bus( this == $bus, color = 'red' ) )
+then
+ # all english buses are red
+end
+</programlisting>
+
+ <para>In the above rule, we "select" all Bus object whose type is
+ "english". Then, for each fact that matches this pattern we evaluate the
+ following patterns and if they match, the forall CE will evaluate to
+ true.</para>
+
+ <para>To state that all facts of a given type in the working memory must
+ match a set of constraints, forall can be written with a single pattern
+ for simplicity. Example</para>
+
+ <para><example>
+ <title>Single Pattern Forall</title>
+
+ <programlisting>rule "All Buses are Red"
+when
+ forall( Bus( color == 'red' ) )
+then
+ # all asserted Bus facts are red
+end
+</programlisting>
+ </example></para>
+
+ <para>Another example of multi-pattern forall:<example>
+ <title>Multi-Pattern Forall</title>
+
+ <programlisting>rule "all employees have health and dental care programs"
+when
+ forall( $emp : Employee()
+ HealthCare( employee == $emp )
+ DentalCare( employee == $emp )
+ )
+then
+ # all employees have health and dental care
+end
+</programlisting>
+ </example></para>
+
+ <para>Forall can be nested inside other CEs for complete expressiveness.
+ For instance, <emphasis role="bold">forall</emphasis> can be used inside
+ a <emphasis role="bold">not</emphasis> CE, note that only single
+ patterns have optional parenthesis, so with a nested forall parenthesis
+ must be used :<example>
+ <title>Combining Forall with Not CE</title>
+
+ <programlisting>rule "not all employees have health and dental care"
+when
+ not ( forall( $emp : Employee()
+ HealthCare( employee == $emp )
+ DentalCare( employee == $emp ) )
+ )
+then
+ # not all employees have health and dental care
+end
+</programlisting>
+ </example></para>
+
+ <para>As a side note, <code>not( forall( p1 p2 p3...))</code> is
+ equivalent to writing:</para>
+
+ <programlisting>not(p1 and not(and p2 p3...))</programlisting>
+
+ <para>Also, it is important to note that <emphasis role="bold">forall is
+ a scope delimiter</emphasis>, so it can use any previously bound
+ variable, but no variable bound inside it will be available to use
+ outside of it.</para>
+ </section>
+
+ <section>
+ <title>From</title>
+
+ <figure>
+ <title>from</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/from.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The <emphasis role="bold">from</emphasis> Conditional Element
+ allows users to specify a source for patterns to reason over. This
+ allows the engine to reason over data not in the Working Memory. This
+ could be a sub-field on a bound variable or the results of a method
+ call. It is a powerful construction that allows out of the box
+ integration with other application components and frameworks. One common
+ example is the integration with data retrieved on-demand from databases
+ using hibernate named queries.</para>
+
+ <para>The expression used to define the object source is any expression
+ that follows regular MVEL syntax. I.e., it allows you to easily use
+ object property navigation, execute method calls and access maps and
+ collections elements.</para>
+
+ <para>Here is a simple example of reasoning and binding on another
+ pattern sub-field:</para>
+
+ <para><programlisting>rule "validate zipcode"
+when
+ Person( $personAddress : address )
+ Address( zipcode == "23920W") from $personAddress
+then
+ # zip code is ok
+end
+</programlisting></para>
+
+ <para>With all the flexibility from the new expressiveness in the Drools
+ engine you can slice and dice this problem many ways. This is the same
+ but shows how you can use a graph notation with the 'from':</para>
+
+ <para><programlisting>rule "validate zipcode"
+when
+ $p : Person( )
+ $a : Address( zipcode == "23920W") from $p.address
+then
+ # zip code is ok
+end
+</programlisting></para>
+
+ <para>Previous examples were reasoning over a single pattern. The
+ <emphasis role="bold">from</emphasis> CE also support object sources
+ that return a collection of objects. In that case, <emphasis
+ role="bold">from</emphasis> will iterate over all objects in the
+ collection and try to match each of them individually. For instance, if
+ we want a rule that applies 10% discount to each item in an order, we
+ could do:</para>
+
+ <programlisting>rule "apply 10% discount to all items over US$ 100,00 in an order"
+when
+ $order : Order()
+ $item : OrderItem( value > 100 ) from $order.items
+then
+ # apply discount to $item
+end
+</programlisting>
+
+ <para>The above example will cause the rule to fire once for each item
+ whose value is greater than 100 for each given order.</para>
+
+ <para>You must take caution, however, when using <emphasis
+ role="bold">from</emphasis>, especially in conjunction with the
+ <emphasis role="bold">lock-on-active</emphasis> rule attribute
+ as it may produce unexpected results. Consider the example provided earlier, but
+ now slightly modified as follows:</para>
+
+ <para><programlisting>rule "Assign people in North Carolina (NC) to sales region 1"
+ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person( )
+ $a : Address( state == "NC") from $p.address
+then
+ modify ($p) {} #Assign person to sales region 1 in a modify block
+end
+
+rule "Apply a discount to people in the city of Raleigh"
+ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person( )
+ $a : Address( city == "Raleigh") from $p.address
+then
+ modify ($p) {} #Apply discount to person in a modify block
+end
+</programlisting></para>
+
+ <para>
+ In the above example, persons in Raleigh, NC should be assigned to sales region 1 and
+ receive a discount; i.e., you would expect both rules to activate and fire. Instead you
+ will find that only the second rule fires.</para>
+
+ <para>If you were to turn on the audit log, you would also see that when the second rule fires,
+ it deactivates the first rule. Since the rule attribute <emphasis role="bold">lock-on-active</emphasis>
+ prevents a rule from creating new activations when a set of facts change, the first rule fails to
+ reactivate. Though the set of facts have not changed, the use of
+ <emphasis role="bold">from</emphasis> returns a new fact for all intents and purposes each time
+ it is evaluated.
+ </para>
+
+ <para>First, it's important to review why you would use the above pattern. You may have
+ many rules across different rule-flow groups. When rules modify working memory and other rules
+ downstream of your RuleFlow (in different rule-flow groups) need to be reevaluated, the use of <emphasis role="bold">modify</emphasis>
+ is critical. You don't, however, want other rules in the same rule-flow group to place
+ activations on one another recursively. In this case, the <emphasis role="bold">no-loop</emphasis>
+ attribute is ineffective, as it would only prevent a rule from activating itself recursively. Hence,
+ you resort to <emphasis role="bold">lock-on-active</emphasis>.
+ </para>
+
+ <para>
+ There are several ways to address this issue:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Avoid the use of <emphasis role="bold">from</emphasis> when you can assert all facts into working memory
+ or use nested object references in your constraint expressions (shown below)</para>
+ </listitem>
+ <listitem>
+ <para>Place the variable assigned used in the modify block as the last sentence in your condition (LHS)</para>
+ </listitem>
+ <listitem>
+ <para>Avoid the use of <emphasis role="bold">lock-on-active</emphasis> when you can
+ explicitly manage how rules within the same rule-flow group place activations on one another
+ (explained below)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The preferred solution is to minimize use of <emphasis role="bold">from</emphasis>
+ when you can assert all your facts into working memory directly. In the example above,
+ both the Person and Address instance can be asserted into working memory. In this case, because
+ the graph is fairly simple, an even easier solution is to modify your rules as follows:
+ </para>
+
+ <para><programlisting>rule "Assign people in North Carolina (NC) to sales region 1"
+ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person(address.state == "NC" )
+then
+ modify ($p) {} #Assign person to sales region 1 in a modify block
+end
+
+rule "Apply a discount to people in the city of Raleigh"
+ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person(address.city == "Raleigh" )
+then
+ modify ($p) {} #Apply discount to person in a modify block
+end
+</programlisting></para>
+
+ <para>Now, you will find that both rules fire as expected. However, it is not
+ always possible to access nested facts as above. Consider an example where a Person
+ holds one or more Addresses and you wish to use an existential quantifier to
+ match people with at least one address that meets certain conditions.
+ In this case, you would have to resort to
+ the use of <emphasis role="bold">from</emphasis> to reason over the collection.</para>
+
+ <para>
+ There are several ways to use <emphasis role="bold">from</emphasis>
+ to achieve this and not all of them exhibit an issue
+ with the use of <emphasis role="bold">lock-on-active</emphasis>. For example,
+ the following use of <emphasis role="bold">from</emphasis> causes both rules to fire as expected:
+ </para>
+
+ <para><programlisting>rule "Assign people in North Carolina (NC) to sales region 1"
+ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person($addresses : addresses)
+ exists (Address(state == "NC") from $addresses)
+then
+ modify ($p) {} #Assign person to sales region 1 in a modify block
+end
+
+rule "Apply a discount to people in the city of Raleigh"
+ruleflow-group "test"
+lock-on-active true
+when
+ $p : Person($addresses : addresses)
+ exists (Address(city == "Raleigh") from $addresses)
+then
+ modify ($p) {} #Apply discount to person in a modify block
+end
+</programlisting></para>
+
+ <para>However, the following slightly different approach does exhibit the problem:</para>
+
+ <para><programlisting>rule "Assign people in North Carolina (NC) to sales region 1"
+ruleflow-group "test"
+lock-on-active true
+when
+ $assessment : Assessment()
+ $p : Person()
+ $addresses : List() from $p.addresses
+ exists (Address( state == "NC") from $addresses)
+then
+ modify ($assessment) {} #Modify assessment in a modify block
+end
+
+rule "Apply a discount to people in the city of Raleigh"
+ruleflow-group "test"
+lock-on-active true
+when
+ $assessment : Assessment()
+ $p : Person()
+ $addresses : List() from $p.addresses
+ exists (Address( city == "Raleigh") from $addresses)
+then
+ modify ($assessment) {} #Modify assessment in a modify block
+end</programlisting></para>
+
+ <para>In the above example, the $addresses variable is returned from the
+ use of <emphasis role="bold">from</emphasis>. The example also introduces
+ a new object, assessment, to highlight one possible solution in this case.
+ If the $assessment variable assigned in the condition (LHS) is moved to the last condition
+ in each rule, both rules fire as expected.
+ </para>
+
+ <para>
+ Though the above examples demonstrate how to combine the use of <emphasis role="bold">from</emphasis>
+ with <emphasis role="bold">lock-on-active</emphasis> where no loss of rule activations occurs,
+ they carry the drawback of placing a dependency on the order of conditions on the LHS. In addition,
+ the solutions present greater complexity for the rule author in terms of keeping track of
+ which conditions may create issues.
+ </para>
+
+ <para>A better alternative is to
+ assert more facts into working memory. In this case, a person's addresses
+ may be asserted into working memory and the use of <emphasis role="bold">from</emphasis>
+ would not be necessary.</para>
+
+ <para>There are cases, however, where asserting all data into working memory is not
+ practical and we need to find other solutions. Another option is to reevaluate the
+ need for <emphasis role="bold">lock-on-active</emphasis>.
+ An alternative to <emphasis role="bold">lock-on-active</emphasis> is to
+ directly manage how rules within the same rule-flow group activate one another
+ by including conditions in each rule that prevent rules from activating each other recursively
+ when working memory is modified. For example, in the case above where a
+ discount is applied to citizens of Raleigh, a condition may be added to the rule
+ that checks whether the discount has already been applied. If so, the rule does not
+ activate.</para>
+
+ </section>
+
+ <section>
+ <title>'collect'</title>
+
+ <figure>
+ <title>collect</title>
+
+ <mediaobject>
+
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/collect.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The <emphasis role="bold">collect</emphasis> Conditional Element
+ allows rules to reason over collection of objects collected from the
+ given source or from the working memory. In first oder logic terms this
+ is Cardinality Quantifier. A simple example:</para>
+
+ <programlisting>import java.util.ArrayList
+
+rule "Raise priority if system has more than 3 pending alarms"
+when
+ $system : System()
+ $alarms : ArrayList( size >= 3 )
+ from collect( Alarm( system == $system, status == 'pending' ) )
+then
+ # Raise priority, because system $system has
+ # 3 or more alarms pending. The pending alarms
+ # are $alarms.
+end
+</programlisting>
+
+ <para>In the above example, the rule will look for all pending alarms in
+ the working memory for each given system and group them in ArrayLists.
+ If 3 or more alarms are found for a given system, the rule will
+ fire.</para>
+
+ <para>The <emphasis role="bold">collect</emphasis> CE result pattern can
+ be any concrete class that implements tha java.util.Collection interface
+ and provides a default no-arg public constructor. I.e., you can use
+ default Java collections like ArrayList, LinkedList, HashSet, etc, or
+ your own class, as long as it implements the java.util.Collection
+ interface and provide a default no-arg public constructor.</para>
+
+ <para>Both source and result patterns can be constrained as any other
+ pattern.</para>
+
+ <para>Variables bound before the <emphasis
+ role="bold">collect</emphasis> CE are in the scope of both source and
+ result patterns and as so, you can use them to constrain both your
+ source and result patterns. Although, the <emphasis>collect( ...
+ )</emphasis> is a scope delimiter for bindings, meaning that any binding
+ made inside of it, is not available for use outside of it.</para>
+
+ <para>Collect accepts nested <emphasis role="bold">from</emphasis>
+ elements, so the following example is a valid use of <emphasis
+ role="bold">collect</emphasis>:</para>
+
+ <programlisting>import java.util.LinkedList;
+
+rule "Send a message to all mothers"
+when
+ $town : Town( name == 'Paris' )
+ $mothers : LinkedList()
+ from collect( Person( gender == 'F', children > 0 )
+ from $town.getPeople()
+ )
+then
+ # send a message to all mothers
+end
+</programlisting>
+ </section>
+
+ <section>
+ <title>'accumulate'</title>
+
+ <figure>
+ <title>accumulate</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" fileref="images/Chapter-Rule_Language/accumulate.png" format="PNG" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The <emphasis role="bold">accumulate</emphasis> Conditional
+ Element is a more flexible and powerful form of <emphasis
+ role="bold">collect</emphasis> Conditional Element, in the sense that it
+ can be used to do what <emphasis role="bold">collect</emphasis> CE does
+ and also do things that <emphasis role="bold">collect</emphasis> CE is
+ not capable to do. Basically what it does is it allows a rule to iterate
+ over a collection of objects, executing custom actions for each of the
+ elements, and at the end return a result object.</para>
+
+ <para>The general syntax of the <emphasis
+ role="bold">accumulate</emphasis> CE is:</para>
+
+ <programlisting><replaceable><result pattern></replaceable> from accumulate( <replaceable><source pattern></replaceable>,
+ init( <replaceable><init code></replaceable> ),
+ action( <replaceable><action code></replaceable> ),
+ reverse( <replaceable><reverse code></replaceable> ),
+ result( <replaceable><result expression></replaceable> ) )
+</programlisting>
+
+ <para>The meaning of each of the elements is the following:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="bold"><source pattern></emphasis>: the
+ source pattern is a regular pattern that the engine will try to
+ match against each of the source objects.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold"><init code></emphasis>: this is a
+ semantic block of code in the selected dialect that will be executed
+ once for each tuple, before iterating over the source
+ objects.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold"><action code></emphasis>: this is
+ a semantic block of code in the selected dialect that will be
+ executed for each of the source objects.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold"><reverse code></emphasis>: this is
+ an optional semantic block of code in the selected dialect that if
+ present will be executed for each source object that no longer
+ matches the source pattern. The objective of this code block is to
+ "undo" any calculation done in the <action code> block, so
+ that the engine can do decremental calculation when a source object
+ is modified or retracted, hugely improving performance of these
+ operations.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold"><result expression></emphasis>:
+ this is a semantic expression in the selected dialect that is
+ executed after all source objects are iterated.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold"><result pattern></emphasis>: this
+ is a regular pattern that the engine tries to match against the
+ object returned from the <result expression>. If it matches,
+ the <emphasis role="bold">accumulate</emphasis> conditional element
+ evaluates to <emphasis role="bold">true</emphasis> and the engine
+ proceeds with the evaluation of the next CE in the rule. If it does
+ not matches, the <emphasis role="bold">accumulate</emphasis> CE
+ evaluates to <emphasis role="bold">false</emphasis> and the engine
+ stops evaluating CEs for that rule.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>It is easier to understand if we look at an example:</para>
+
+ <programlisting>rule "Apply 10% discount to orders over US$ 100,00"
+when
+ $order : Order()
+ $total : Number( doubleValue > 100 )
+ from accumulate( OrderItem( order == $order, $value : value ),
+ init( double total = 0; ),
+ action( total += $value; ),
+ reverse( total -= $value; ),
+ result( total ) )
+then
+ # apply discount to $order
+end
+</programlisting>
+
+ <para>In the above example, for each Order() in the working memory, the
+ engine will execute the <emphasis role="bold">init code</emphasis>
+ initializing the total variable to zero. Then it will iterate over all
+ OrderItem() objects for that order, executing the <emphasis
+ role="bold">action</emphasis> for each one (in the example, it will sum
+ the value of all items into the total variable). After iterating over
+ all OrderItem, it will return the value corresponding to the <emphasis
+ role="bold">result expression</emphasis> (in the above example, the
+ value of the total variable). Finally, the engine will try to match the
+ result with the Number() pattern and if the double value is greater than
+ 100, the rule will fire.</para>
+
+ <para>The example used Java as the semantic dialect, and as such, note
+ that the usage of ';' is mandatory in the init, action and reverse code
+ blocks. The result is an expression and as such, it does not admit ';'.
+ If the user uses any other dialect, he must comply to that dialect
+ specific syntax.</para>
+
+ <para>As mentioned before, the <emphasis role="bold">reverse
+ code</emphasis> is optional, but it is strongly recommended that the
+ user writes it in order to benefit from the <emphasis>improved
+ performance on update and retracts</emphasis>.</para>
+
+ <para>The <emphasis role="bold">accumulate</emphasis> CE can be used to
+ execute any action on source objects. The following example instantiates
+ and populates a custom object:</para>
+
+ <programlisting>rule "Accumulate using custom objects"
+when
+ $person : Person( $likes : likes )
+ $cheesery : Cheesery( totalAmount > 100 )
+ from accumulate( $cheese : Cheese( type == $likes ),
+ init( Cheesery cheesery = new Cheesery(); ),
+ action( cheesery.addCheese( $cheese ); ),
+ reverse( cheesery.removeCheese( $cheese ); ),
+ result( cheesery ) );
+then
+ // do something
+end</programlisting>
+
+ <section>
+ <title>Accumulate Functions</title>
+
+ <para>The accumulate CE is a very powerful CE, but it gets real
+ declarative and easy to use when using predefined functions that are
+ known as Accumulate Functions. They work exactly like accumulate, but
+ instead of explicitly writing custom code in every accumulate CE, the
+ user can use predefined code for common operations.</para>
+
+ <para>For instance, the rule to apply discount on orders written in
+ the previous section, could be written in the following way, using
+ Accumulate Functions:</para>
+
+ <programlisting>rule "Apply 10% discount to orders over US$ 100,00"
+when
+ $order : Order()
+ $total : Number( doubleValue > 100 )
+ from accumulate( OrderItem( order == $order, $value : value ),
+ sum( $value ) )
+then
+ # apply discount to $order
+end
+</programlisting>
+
+ <para>In the above example, sum is an Accumulate Function and will sum
+ the $value of all OrderItems and return the result.</para>
+
+ <para>Drools 4.0 ships with the following built in accumulate
+ functions:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>average</para>
+ </listitem>
+
+ <listitem>
+ <para>min</para>
+ </listitem>
+
+ <listitem>
+ <para>max</para>
+ </listitem>
+
+ <listitem>
+ <para>count</para>
+ </listitem>
+
+ <listitem>
+ <para>sum</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>These common functions accept any expression as input. For
+ instance, if someone wants to calculate the average profit on all
+ items of an order, a rule could be written using the average
+ function:</para>
+
+ <programlisting>rule "Average profit"
+when
+ $order : Order()
+ $profit : Number()
+ from accumulate( OrderItem( order == $order, $cost : cost, $price : price )
+ average( 1 - $cost / $price ) )
+then
+ # average profit for $order is $profit
+end
+</programlisting>
+
+ <para>Accumulate Functions are all pluggable. That means that if
+ needed, custom, domain specific functions can easily be added to the
+ engine and rules can start to use them without any restrictions. To
+ implement a new Accumulate Functions all one needs to do is to create
+ a Java class that implements the
+ org.drools.base.acumulators.AccumulateFunction interface and add a
+ line to the configuration file or set a system property to let the
+ engine know about the new function. As an example of an Accumulate
+ Function implementation, the following is the implementation of the
+ "average" function:</para>
+
+ <programlisting>/*
+ * Copyright 2007 JBoss Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Created on Jun 21, 2007
+ */
+package org.drools.base.accumulators;
+
+
+/**
+ * An implementation of an accumulator capable of calculating average values
+ *
+ * @author etirelli
+ *
+ */
+public class AverageAccumulateFunction implements AccumulateFunction {
+
+ protected static class AverageData {
+ public int count = 0;
+ public double total = 0;
+ }
+
+ /* (non-Javadoc)
+ * @see org.drools.base.accumulators.AccumulateFunction#createContext()
+ */
+ public Object createContext() {
+ return new AverageData();
+ }
+
+ /* (non-Javadoc)
+ * @see org.drools.base.accumulators.AccumulateFunction#init(java.lang.Object)
+ */
+ public void init(Object context) throws Exception {
+ AverageData data = (AverageData) context;
+ data.count = 0;
+ data.total = 0;
+ }
+
+ /* (non-Javadoc)
+ * @see org.drools.base.accumulators.AccumulateFunction#accumulate(java.lang.Object, java.lang.Object)
+ */
+ public void accumulate(Object context,
+ Object value) {
+ AverageData data = (AverageData) context;
+ data.count++;
+ data.total += ((Number) value).doubleValue();
+ }
+
+ /* (non-Javadoc)
+ * @see org.drools.base.accumulators.AccumulateFunction#reverse(java.lang.Object, java.lang.Object)
+ */
+ public void reverse(Object context,
+ Object value) throws Exception {
+ AverageData data = (AverageData) context;
+ data.count--;
+ data.total -= ((Number) value).doubleValue();
+ }
+
+ /* (non-Javadoc)
+ * @see org.drools.base.accumulators.AccumulateFunction#getResult(java.lang.Object)
+ */
+ public Object getResult(Object context) throws Exception {
+ AverageData data = (AverageData) context;
+ return new Double( data.count == 0 ? 0 : data.total / data.count );
+ }
+
+ /* (non-Javadoc)
+ * @see org.drools.base.accumulators.AccumulateFunction#supportsReverse()
+ */
+ public boolean supportsReverse() {
+ return true;
+ }
+
+}
+</programlisting>
+
+ <para>The code for the function is very simple, as we could expect, as
+ all the "dirty" integration work is done by the engine. Finally, to
+ plug the function into the engine, we added it to the configuration
+ file:</para>
+
+ <programlisting>drools.accumulate.function.average = org.drools.base.accumulators.AverageAccumulateFunction
+</programlisting>
+
+ <para>Where "drools.accumulate.function." is a prefix that must always
+ be used, "average" is how the function will be used in the rule file,
+ and "org.drools.base.accumulators.AverageAccumulateFunction" is the
+ fully qualified name of the class that implements the function
+ behavior.</para>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>The Right Hand Side (then)</title>
+
+ <para>The Right Hand Side (RHS) is a common name for the consequence or
+ action part of the rule; this part should contain a list of actions to be
+ executed. It is bad practice to use imperative or conditional code in the
+ RHS of a rule; as a rule should be atomic in nature - "when this, then do
+ this", not "when this, maybe do this". The RHS part of a rule should also
+ be kept small, thus keeping it declarative and readable. If you find you
+ need imperative and/or conditional code in the RHS, then maybe you should
+ be breaking that rule down into multiple rules. The main purpose of the
+ RHS is to insert, retractor modify working memory data. To assist with
+ that there are a few convenience methods you can use to modify working
+ memory; without having to first reference a working memory
+ instance.</para>
+
+ <para>"update(object, handle);" will tell the engine that an object has
+ changed (one that has been bound to something on the LHS) and rules may
+ need to be reconsidered.</para>
+
+ <para>"update(object);" can also be used, here the KnowledgeHelper will
+ lookup the facthandle for you, via an identity check, for the passed object.</para>
+
+ <para>"insert(new Something());" will place a new object of your creation
+ in working memory.</para>
+
+ <para>"insertLogical(new Something());" is similar to insert, but the
+ object will be automatically retracted when there are no more facts to
+ support the truth of the currently firing rule.</para>
+
+ <para>"retract(handle);" removes an object from working memory.</para>
+
+ <para>These convenience methods are basically macros that provide short
+ cuts to the KnowledgeHelper instance (refer to the KnowledgeHelper
+ interface for more advanced operations). The KnowledgeHelper interface is
+ made available to the RHS code block as a variable called "drools". If you
+ provide "Property Change Listeners" to your Java beans that you are
+ inserting into the engine, you can avoid the need to call "update" when
+ the object changes.</para>
+ </section>
+
+ <section>
+ <title>A note on auto boxing/unboxing and primitive types</title>
+
+ <para>Drools attempts to preserve numbers in their primitive or object
+ wrapper form, so a variable bound to an int primitive when used in a code
+ block or expression will no longer need manual unboxing; unlike Drools 3.0
+ where all primitives was autoboxed, requiring manual unboxing. A variable
+ bound to an object wrapper will remain as an object; the existing jdk1.5
+ and jdk5 rules to handling auto boxing/unboxing apply in this case. When
+ evaluating field constraints the system attempts to coerce one of the
+ values into a comparable format; so a primitive is comparable to an object
+ wrapper.</para>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-TypeDeclaration.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-TypeDeclaration.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-TypeDeclaration.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,332 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
+ <title>Type Declaration</title>
+
+ <note>
+ <para><replaceable>(updated to Drools 5.0)</replaceable></para>
+ </note>
+
+ <warning>
+ <para>FIXME: add syntax diagram for declare</para>
+ </warning>
+
+ <para>Type declarations have two main goals in the rules engine: to allow the
+ declaration of new types, and to allow the declaration of metadata for
+ types.</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="bold">Declaring new types:</emphasis> Drools works
+ out of the box with plain POJOs as facts. Although, sometimes the users
+ may want to define the model directly to the rules engine, without
+ worrying to create their models in a lower level language like Java.
+ At other times, there is a domain model already built, but eventually the
+ user wants or needs to complement this model with additional entities
+ that are used mainly during the reasoning process.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold">Declaring metadata:</emphasis> facts may
+ have meta information associated to them. Examples of meta information
+ include any kind of data that is not represented by the fact attributes
+ and are consistent among all instances of that fact type. This meta
+ information may be queried at runtime by the engine and used in the
+ reasoning process.</para>
+ </listitem>
+ </itemizedlist>
+
+ <section>
+ <title>Declaring New Types</title>
+
+ <para>To declare a new type, all you need to do is use the keyword
+ <emphasis role="bold">declare</emphasis>, followed by the list of fields
+ and the keyword <emphasis role="bold">end</emphasis>.</para>
+
+ <example>
+ <title>declaring a new fact type: Address</title>
+
+ <programlisting><emphasis role="bold">declare</emphasis> Address
+ number : int
+ streetName : String
+ city : String
+<emphasis role="bold">end</emphasis>
+</programlisting>
+ </example>
+
+ <para>The previous example declares a new fact type called
+ <emphasis>Address</emphasis>. This fact type will have 3 attributes:
+ <emphasis>number</emphasis>, <emphasis>streetName</emphasis> and
+ <emphasis>city</emphasis>. Each attribute has a type that can be any valid
+ Java type, including any other class created by the user or even other
+ fact types previously declared.</para>
+
+ <para>For instance, we may want to declare another fact type
+ <emphasis>Person</emphasis>:</para>
+
+ <para><example>
+ <title>declaring a new fact type: Person</title>
+
+ <programlisting><emphasis role="bold">declare</emphasis> Person
+ name : String
+ dateOfBirth : java.util.Date
+ address : Address
+<emphasis role="bold">end</emphasis>
+</programlisting>
+ </example>As we can see on the previous example,
+ <emphasis>dateOfBirth</emphasis> is of type <code>java.util.Date</code>,
+ from the Java API, while <emphasis>address</emphasis> is of the previously
+ defined fact type Address.</para>
+
+ <para>You may avoid having to write the fully qualified name of a class
+ every time you write it by using the <emphasis
+ role="bold">import</emphasis> clause, previously discussed.</para>
+
+ <para><example>
+ <title>avoiding the need to use fully qualified class names by using
+ import</title>
+
+ <programlisting><emphasis role="bold">import</emphasis> java.util.Date
+
+<emphasis role="bold">declare</emphasis> Person
+ name : String
+ dateOfBirth : Date
+ address : Address
+<emphasis role="bold">end</emphasis></programlisting>
+ </example></para>
+
+ <para>When you declare a new fact type, Drools will, at compile time,
+ generate bytecode implementing a POJO that represents the fact type. The generated Java
+ class will be a one-to-one Java Bean mapping of the type definition. So,
+ for the previous example, the generated Java class would be:</para>
+
+ <para><example>
+ <title>generated Java class for the previous Person fact type
+ declaration</title>
+
+ <programlisting><emphasis role="bold">public</emphasis> <emphasis
+ role="bold">class</emphasis> Person implements Serializable {
+ <emphasis role="bold">private</emphasis> String name;
+ <emphasis role="bold">private</emphasis> java.util.Date dateOfBirth;
+ <emphasis role="bold">private</emphasis> Address address;
+
+ // getters and setters
+ // equals/hashCode
+ // toString
+}
+</programlisting>
+ </example>Since it is a simple POJO, the generated class can be used
+ transparently in the rules, like any other fact.</para>
+
+ <para><example>
+ <title>using the declared types in rules</title>
+
+ <programlisting><emphasis role="bold">rule</emphasis> "Using a declared Type"
+<emphasis role="bold">when</emphasis>
+ $p : Person( name == "Bob" )
+<emphasis role="bold">then</emphasis>
+ System.out.println( "The name of the person is "+ )
+ <emphasis>// lets insert Mark, that is Bob's mate</emphasis>
+ Person mark = new Person();
+ mark.setName("Mark");
+ insert( mark );
+<emphasis role="bold">end</emphasis>
+</programlisting>
+ </example></para>
+ </section>
+
+ <section>
+ <title>Declaring Metadata</title>
+
+ <para>Metadata may be assigned to several different constructions in
+ Drools, like fact types, fact attributes and rules. Drools uses the
+ <emphasis role="bold">@</emphasis> symbol to introduce metadata, and it
+ always uses the form:</para>
+
+ <para><programlisting>@matadata_key( metadata_value )</programlisting>The
+ parenthesis and the metadata_value are optional.</para>
+
+ <para>For instance, if you want to declare a metadata attribute like
+ <emphasis>author</emphasis>, whose value is <emphasis>Bob</emphasis>, you
+ could simply write:</para>
+
+ <example>
+ <title>declaring an arbitrary metadata attribute</title>
+
+ <programlisting>@author( Bob )</programlisting>
+ </example>
+
+ <para>Drools allows the declaration of any arbitrary metadata attribute,
+ but some will have special meaning to the engine, while others are simply
+ available for querying at runtime. Drools allows the declaration of
+ metadata both for fact types and for fact attributes. Any metadata that is
+ declared before the fields of a fact type are assigned to the fact type,
+ while metadata declared after an attribute are assigned to the attribute
+ in particular.</para>
+
+ <example>
+ <title>declaring metadata attributes for fact types and
+ attributes</title>
+
+ <programlisting><emphasis role="bold">import</emphasis> java.util.Date
+
+<emphasis role="bold">declare</emphasis> Person
+ <emphasis>@author</emphasis>( Bob )
+ <emphasis>@dateOfCreation</emphasis>( 01-Feb-2009 )
+
+ name : String <emphasis>@key @maxLength</emphasis>( 30 )
+ dateOfBirth : Date
+ address : Address
+<emphasis role="bold">end</emphasis></programlisting>
+ </example>
+
+ <para>In the previous example, there are two metadata declared for the
+ fact type (<emphasis>@author</emphasis> and
+ <emphasis>@dateOfCreation</emphasis>), and two more defined for the name
+ attribute (<emphasis>@key</emphasis> and <emphasis>@maxLength</emphasis>).
+ Please note that the <emphasis>@key</emphasis> metadata has no value, and
+ so the parenthesis and the value were omitted.</para>
+ </section>
+
+ <section>
+ <title>Declaring Metadata for Existing Types</title>
+
+ <para>Drools allows the declaration of metadata attributes for existing
+ types in the same way as when declaring metadata attributes for new fact
+ types. The only difference is that there are no fields in that
+ declaration.</para>
+
+ <para>For instance, if there is a class org.drools.examples.Person, and
+ one wants to declare metadata for it, just write the following code:</para>
+
+ <example>
+ <title>declaring metadata for an existing type</title>
+
+ <programlisting><emphasis role="bold">import</emphasis> org.drools.examples.Person
+
+<emphasis role="bold">declare</emphasis> Person
+ <emphasis>@author</emphasis>( Bob )
+ <emphasis>@dateOfCreation</emphasis>( 01-Feb-2009 )
+<emphasis role="bold">end</emphasis>
+</programlisting>
+ </example>
+
+ <para>Instead of using the import, it is also possible to reference the
+ class by its fully qualified name, but since the class will also be
+ referenced in the rules, usually it is shorter to add the import and use
+ the short class name everywhere.</para>
+
+ <example>
+ <title>declaring metadata using the fully qualified class name</title>
+
+ <programlisting><emphasis role="bold">declare</emphasis> org.drools.examples.Person
+ <emphasis>@author</emphasis>( Bob )
+ <emphasis>@dateOfCreation</emphasis>( 01-Feb-2009 )
+<emphasis role="bold">end</emphasis></programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>Accessing Declared Types from the Application Code</title>
+
+ <para>Declared types are usually used inside rules files, while Java
+ models are used when sharing the model between rules and applications.
+ Although, sometimes, the application may need to access and handle facts
+ from the declared types, specially when the application is wrapping the
+ rules engine and providing higher level, domain specific, user interfaces
+ for rules management.</para>
+
+ <para>In such cases, the generated classes can be handled as usual with
+ the Java Reflection APIs, but as we know, that usually requires a lot of
+ work for small results. This way, Drools provides a simplified API for the
+ most common fact handling the application may want to do.</para>
+
+ <para>The first important thing to realize is that a declared fact will
+ belong to the package where it was declared. So, for instance, in the
+ example below, <emphasis>Person</emphasis> will belong to the
+ <emphasis>org.drools.examples</emphasis> package, and so the generated
+ class fully qualified name will be:
+ <emphasis>org.drools.examples.Person</emphasis>.</para>
+
+ <example>
+ <title>declaring a type in the org.drools.examples package</title>
+
+ <programlisting><emphasis role="bold">package</emphasis> org.drools.examples
+
+<emphasis role="bold">import</emphasis> java.util.Date
+
+<emphasis role="bold">declare</emphasis> Person
+ name : String
+ dateOfBirth : Date
+ address : Address
+<emphasis role="bold">end</emphasis></programlisting>
+ </example>
+
+ <para>Declared types, as discussed previously, are generated at knowledge
+ base compilation time, i.e., the application will only have access to them
+ at application run time. As so, these classes are not available for direct
+ reference from the application. </para>
+
+ <para>Drools then provides an interface through which the users can handle
+ declared types from the application code:
+ org.drools.definition.type.FactType. Through this interface, the user can
+ instantiate, read and write fields in the declared fact types.</para>
+
+ <example>
+ <title>handling declared fact types through the API</title>
+
+ <programlisting>// get a reference to a knowledge base with a declared type:
+KnowledgeBase kbase = ...
+
+// get the declared FactType
+FactType personType = kbase.getFactType( "org.drools.examples",
+ "Person" );
+
+// handle the type as necessary:
+// create instances:
+Object bob = personType.newInstance();
+
+// set attributes values
+personType.set( bob,
+ "name",
+ "Bob" );
+personType.set( bob,
+ "age",
+ 42 );
+
+// insert fact into a session
+StatefulKnowledgeSession ksession = ...
+ksession.insert( bob );
+ksession.fireAllRules();
+
+// read attributes
+String name = personType.get( bob, "name" );
+int age = personType.get( bob, "age" );
+
+</programlisting>
+ </example>
+
+ <para>The API also includes other helpful methods, like setting all the
+ attributes at once, reading values from a Map, or read all attributes at
+ once, populating a Map. </para>
+
+ <para>Although the API is similar to Java reflection (yet much simpler to
+ use), it does not use reflection underneath, relying in much more
+ performant bytecode generated accessors.</para>
+
+ <para></para>
+
+ <para></para>
+
+ <para></para>
+
+ <para></para>
+
+ <para></para>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-XML.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-XML.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Language_Reference/Section-XML.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,335 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <section 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"
+ xmlns:db="http://docbook.org/ns/docbook" xml:base="../../">
+ <title>XML Rule Language</title>
+
+ <para>As an option, Drools also supports a "native" <indexterm>
+ <primary>XML</primary>
+ </indexterm> rule language as an alternative to DRL. This allows you to
+ capture and manage your rules as XML data. Just like the non-XML DRL format,
+ the XML format is parsed into the internal "AST" representation - as fast as
+ possible (using a SAX parser). There is no external transformation step
+ required. All the features are available with XML that are available to
+ DRL.</para>
+
+ <section>
+ <title>When to use XML</title>
+
+ <para>There are several scenarios that XML is desirable. However, we
+ recommend that it is not a default choice, as XML is not readily human
+ readable (unless you like headaches) and can create visually bloated
+ rules.</para>
+
+ <para>If you do want to edit XML by hand, use a good schema aware editor
+ that provides nice hierarchical views of the XML, ideally visually
+ (commercial tools like XMLSpy, Oxygen etc are good, but cost money, but
+ then so do headache tablets).</para>
+
+ <para>Other scenarios where you may want to use the XML format are if you
+ have a tool that generates rules from some input (programmatically
+ generated rules), or perhaps interchange from another rule language, or
+ from another tool that emits XML (using XSLT you can easily transform
+ between XML formats). Note you can always generate normal DRL as
+ well.</para>
+
+ <para>Alternatively you may be embedding Drools in a product that already
+ uses XML for configuration, so you would like the rules to be in an XML
+ format. You may be creating your own rule language on XML - note that you
+ can always use the AST objects directly to create your own rule language
+ as well (the options are many, due to the open architecture).</para>
+ </section>
+
+ <section>
+ <title>The XML format</title>
+
+ <para>A full W3C standards (XMLSchema) compliant XSD is provided that
+ describes the XML language, which will not be repeated here verbatim. A
+ summary of the language follows.</para>
+
+ <example>
+ <title>A rule in XML<indexterm>
+ <primary>XML Rule</primary>
+ </indexterm></title>
+
+ <programlisting><?xml version="1.0" encoding="UTF-8"?>
+
+<package name="com.sample"
+ xmlns="http://drools.org/drools-4.0"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
+ xs:schemaLocation="http://drools.org/drools-4.0 drools-4.0.xsd">
+
+<import name="java.util.HashMap" />
+<import name="org.drools.*" />
+
+<global identifier="x" type="com.sample.X" />
+<global identifier="yada" type="com.sample.Yada" />
+
+<function return-type="void" name="myFunc">
+ <parameter identifier="foo" type="Bar" />
+ <parameter identifier="bada" type="Bing" />
+
+ <body>
+ System.out.println("hello world");
+ </body>
+</function>
+
+<rule name="simple_rule">
+<rule-attribute name="salience" value="10" />
+<rule-attribute name="no-loop" value="true" />
+<rule-attribute name="agenda-group" value="agenda-group" />
+<rule-attribute name="activation-group" value="activation-group" />
+
+<lhs>
+ <pattern identifier="foo2" object-type="Bar" >
+ <or-constraint-connective>
+ <and-constraint-connective>
+ <field-constraint field-name="a">
+ <or-restriction-connective>
+ <and-restriction-connective>
+ <literal-restriction evaluator=">" value="60" />
+ <literal-restriction evaluator="<" value="70" />
+ </and-restriction-connective>
+ <and-restriction-connective>
+ <literal-restriction evaluator="<" value="50" />
+ <literal-restriction evaluator=">" value="55" />
+ </and-restriction-connective>
+ </or-restriction-connective>
+ </field-constraint>
+
+ <field-constraint field-name="a3">
+ <literal-restriction evaluator="==" value="black" />
+ </field-constraint>
+ </and-constraint-connective>
+
+ <and-constraint-connective>
+ <field-constraint field-name="a">
+ <literal-restriction evaluator="==" value="40" />
+ </field-constraint>
+
+ <field-constraint field-name="a3">
+ <literal-restriction evaluator="==" value="pink" />
+ </field-constraint>
+ </and-constraint-connective>
+
+ <and-constraint-connective>
+ <field-constraint field-name="a">
+ <literal-restriction evaluator="==" value="12"/>
+ </field-constraint>
+
+ <field-constraint field-name="a3">
+ <or-restriction-connective>
+ <literal-restriction evaluator="==" value="yellow"/>
+ <literal-restriction evaluator="==" value="blue" />
+ </or-restriction-connective>
+ </field-constraint>
+ </and-constraint-connective>
+ </or-constraint-connective>
+ </pattern>
+
+ <not>
+ <pattern object-type="Person">
+ <field-constraint field-name="likes">
+ <variable-restriction evaluator="==" identifier="type"/>
+ </field-constraint>
+ </pattern>
+
+ <exists>
+ <pattern object-type="Person">
+ <field-constraint field-name="likes">
+ <variable-restriction evaluator="==" identifier="type"/>
+ </field-constraint>
+ </pattern>
+ </exists>
+ </not>
+
+ <or-conditional-element>
+ <pattern identifier="foo3" object-type="Bar" >
+ <field-constraint field-name="a">
+ <or-restriction-connective>
+ <literal-restriction evaluator="==" value="3" />
+ <literal-restriction evaluator="==" value="4" />
+ </or-restriction-connective>
+ </field-constraint>
+ <field-constraint field-name="a3">
+ <literal-restriction evaluator="==" value="hello" />
+ </field-constraint>
+ <field-constraint field-name="a4">
+ <literal-restriction evaluator="==" value="null" />
+ </field-constraint>
+ </pattern>
+
+ <pattern identifier="foo4" object-type="Bar" >
+ <field-binding field-name="a" identifier="a4" />
+ <field-constraint field-name="a">
+ <literal-restriction evaluator="!=" value="4" />
+ <literal-restriction evaluator="!=" value="5" />
+ </field-constraint>
+ </pattern>
+ </or-conditional-element>
+
+ <pattern identifier="foo5" object-type="Bar" >
+ <field-constraint field-name="b">
+ <or-restriction-connective>
+ <return-value-restriction evaluator="==" >a4 + 1</return-value-restriction>
+ <variable-restriction evaluator=">" identifier="a4" />
+ <qualified-identifier-restriction evaluator="==">
+ org.drools.Bar.BAR_ENUM_VALUE
+ </qualified-identifier-restriction>
+ </or-restriction-connective>
+ </field-constraint>
+ </pattern>
+
+ <pattern identifier="foo6" object-type="Bar" >
+ <field-binding field-name="a" identifier="a4" />
+ <field-constraint field-name="b">
+ <literal-restriction evaluator="==" value="6" />
+ </field-constraint>
+ </pattern>
+ </lhs>
+ <rhs>
+ if ( a == b ) {
+ assert( foo3 );
+ } else {
+ retract( foo4 );
+ }
+ System.out.println( a4 );
+ </rhs>
+</rule>
+
+</package>
+
+</programlisting>
+ </example>
+
+ <para>In the preceding XML text you will see the typical XML
+ element, the package declaration, imports, globals, functions,
+ and the rule itself. Most of the elements are self explanatory
+ if you have some understanding of the Drools features.</para>
+
+ <para>The <code>import</code> elements import the types you wish to
+ use in the rule.</para>
+
+ <para>The <code>global</code> elements define global objects that can
+ be referred to in the rules.</para>
+
+ <para>The <code>function</code> contains a function declaration, for
+ a function to be used in the rules. You have to specify a return type,
+ a unique name and parameters, in the body goes a snippet of code.</para>
+
+ <para>The rule is discussed below.</para>
+
+ <example>
+ <title>Detail of rule element</title>
+
+ <programlisting><rule name="simple_rule">
+<rule-attribute name="salience" value="10" />
+<rule-attribute name="no-loop" value="true" />
+<rule-attribute name="agenda-group" value="agenda-group" />
+<rule-attribute name="activation-group" value="activation-group" />
+
+<lhs>
+ <pattern identifier="cheese" object-type="Cheese">
+ <from>
+ <accumulate>
+ <pattern object-type="Person"></pattern>
+ <init>
+ int total = 0;
+ </init>
+ <action>
+ total += $cheese.getPrice();
+ </action>
+ <result>
+ new Integer( total ) );
+ </result>
+ </accumulate>
+ </from>
+ </pattern>
+
+ <pattern identifier="max" object-type="Number">
+ <from>
+ <accumulate>
+ <pattern identifier="cheese" object-type="Cheese"></pattern>
+ <external-function evaluator="max" expression="$price"/>
+ </accumulate>
+ </from>
+ </pattern>
+</lhs>
+<rhs>
+ list1.add( $cheese );
+</rhs>
+</rule>
+ </programlisting>
+ </example>
+
+ <para>In the above detail of the rule we see that the rule has LHS
+ and RHS (conditions and consequence) sections.
+ The RHS is simple, it is just a block of semantic code that will be
+ executed when the rule is activated. The LHS is slightly more
+ complicated as it contains nested elements for conditional elements,
+ constraints and restrictions.</para>
+
+
+<!--
+ TODO: explain about
+
+ conditional-element
+ constraint-connective
+ restriction-connective
+
+ accumulate and external functions
+-->
+
+ <para>A key element of the LHS is the Pattern element. This allows you to
+ specify a type (class) and perhaps bind a variable to an instance of that
+ class. Nested under the pattern object are constraints and restrictions
+ that have to be met. The Predicate and Return Value constraints
+ allow Java expressions to be embedded.</para>
+
+ <para>That leaves the conditional elements, not, exists, and, or etc. They
+ work like their DRL counterparts. Elements that are nested under and an
+ "and" element are logically "anded" together. Likewise with "or" (and you
+ can nest things further). "Exists" and "Not" work around patterns, to check
+ for the existence or nonexistence of a fact meeting the pattern's
+ constraints.</para>
+
+ <para>The Eval element allows the execution of a valid snippet of Java
+ code - as long as it evaluates to a boolean (do not end it with a
+ semi-colon, as it is just a fragment) - this can include calling a
+ function. The Eval is less efficient than the columns, as the rule engine
+ has to evaluate it each time, but it is a "catch all" feature for when you
+ can express what you need to do with Column constraints.</para>
+ </section>
+
+ <section>
+ <title>Legacy Drools 2.x XML rule format</title>
+ <para>The Drools 2.x legacy XML format is no longer supported by Drools XML parser</para>
+ </section>
+
+ <section>
+ <title>Automatic transforming between formats (XML and DRL)</title>
+
+ <para>Drools comes with some utility classes to transform between formats.
+ This works by parsing the rules from the source format into the AST, and
+ then "dumping" out to the appropriate target format. This allows you, for
+ example, to write rules in DRL, and when needed, export to XML if
+ necessary at some point in the future.</para>
+
+ <para>The classes to look at if you need to do this are: <programlisting>XmlDumper - for exporting XML.
+DrlDumper - for exporting DRL.
+DrlParser - reading DRL.
+XmlPackageReader - reading XML.
+</programlisting> Using combinations of the above, you can convert between any
+ format (including round trip). Note that DSLs will not be preserved (from
+ DRLs that are using a DSL) - but they will be able to be converted.</para>
+
+<para>Feel free to make use of XSLT to provide all sorts of possibilities
+ for XML, XSLT and its ilk are what make XML powerful.</para>
+
+ </section>
+
+</section>
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-04-16 11:50:03 UTC (rev 26060)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Chapter-Quick_Start.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<chapter version="5.0" xml:base="./" xmlns="http://docbook.org/ns/docbook"
+<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"
@@ -8,1329 +8,8 @@
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>
-
- <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>
- </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>
-
- <programlisting>public class Applicant {
- private String name;
- private int age;
- private boolean valid;
- // 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>
-
- <programlisting>package com.company.license
-
-rule "Is of valid age"
-when
- $a : Applicant( age < 18 )
-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>
-
- <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>
-
- <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>
-
- <programlisting>public class Applicant {
- private String name;
- private int age;
- // getter and setter methods here
-}
-
-
-public class Application {
- private Date dateApplied;
- 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>
-
- <programlisting>package com.company.license
-
-rule "Is of valid age"
-when
- Applicant( age < 18 )
- $a : Application()
-then
- $a.setValid( false );
-end
-
-rule "Application was made this year"
-when
- $a : Application( dateApplied > "01-jan-2009" )
-then
- $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>
-
- <programlisting>StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
-Applicant applicant = new Applicant( "Mr John Smith", 16 );
-Application application = new Application();
-assertTrue( application() );
-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).</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>
-
- <itemizedlist>
- <listitem>
- <para>Monitoring</para>
-
- <itemizedlist>
- <listitem>
- <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>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
-
- <para>Unlike a stateless session the dispose() method must be called
- afterwards to ensure there are no memory leaks, as the KnowledgeBase
- contains 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
-}
-public classs Sprinkler {
- private Room room;
- private boolean on;
- // getter and setter methods here
-}
-public class Fire {
- private room room;
- // getter and setter methods here
-}
-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>
-
- <programlisting>rule "When there is a fire turn on the sprinkler"
-when
- Fire($room : room)
- $sprinkler : Sprinkler( room == $room, on == false )
-then
- 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>
-
- <programlisting>rule "When the fire is gone turn on the sprinkler"
-when
- $room : Room( )
- $sprinkler : Sprinkler( room == $room, on == true )
- not Fire( room == $room )
-then
- 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>
-
- <programlisting>rule "Raise the alarm when we have one or more fires"
-when
- exists Fire()
-then
- 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>
-
- <programlisting>rule "Lower the alarm when all the fires have gone"
-when
- not Fire()
- $alarm : Alarm()
-then
- retract( $alarm );
- System.out.println( "Lower the alarm" );
-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>
-
- <programlisting>rule "Status output when things are ok"
-when
- not Alarm()
- not Sprinkler( on === true )
-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>
-
- <programlisting>KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
-kbuilder.add( ResourceFactory.newClasspathResource( "fireAlarm.drl", getClass() ),
- ResourceType.DRL );
-if ( kbuilder.hasErrors() ) {
- 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>
-
- <programlisting>Room kitchen = new Room( "kitchen" );
-Room bedroom = new Room( "bedroom" );
-Room office = new Room( "office" );
-Room livingRoom = new Room( "livingroom" );
-
-ksession.insert( kitchen );
-ksession.insert( bedroom );
-ksession.insert( office );
-ksession.insert( livingRoom );
-
-Sprinkler kitchenSprinkler = new Sprinkler( kitchen );
-Sprinkler bedroomSprinkler = new Sprinkler( bedroom );
-Sprinkler officeSprinkler = new Sprinkler( office );
-Sprinkler livingRoomSprinkler = new Sprinkler( livingRoom );
-
-
-ksession.insert( kitchenSprinkler );
-ksession.insert( bedroomSprinkler );
-ksession.insert( officeSprinkler );
-ksession.insert( livingRoomSprinkler );
-
-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>
-
- <programlisting>Fire kitchenFire = new Fire( kitchen );
-Fire officeFire = new Fire( office );
-
-FactHandle kitchenFireHandle = kession.insert( kitchenFire );
-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>
-
- <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>
- </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>
-
- <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>
- </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>
-
- <programlisting>rule
-when
- $room : Room()
- $sprinkler : Sprinkler()
-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>
-
- <programlisting>room:office sprinker:office
-room:office sprinker:kitchen
-room:office sprinker:livingroom
-room:office sprinker:bedroom
-room:kitchen sprinker:office
-room:kitchen sprinker:kitchen
-room:kitchen sprinker:livingroom
-room:kitchen sprinker:bedroom
-room:livingroom sprinker:office
-room:livingroom sprinker:kitchen
-room:livingroom sprinker:livingroom
-room:livingroom sprinker:bedroom
-room:bedroom sprinker:office
-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>
-
- <programlisting>rule
-when
- $room : Room()
- $sprinkler : Sprinkler( room == $room )
-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>
-
- <programlisting>room:office sprinker:office
-room:kitchen sprinker:kitchen
-room:livingroom sprinker:livingroom
-room:bedroom sprinker:bedroom</programlisting>
- </section>
-
- <section>
- <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;
- private int type;
- long accountNo;
- // getter and setter methods here
-}
-
-public class Account {
- private long accountNo;
- private double balance;
- // getter and setter methods here
-}
-
-public AccountPeriod {
- private Date start;
- 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>
-
- <table border="0">
- <tbody>
- <tr>
- <td align="left" valign="top">
- <table border="1" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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>
- </table>
- </td>
- </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>
-
- <informaltable frame="void">
- <tbody>
- <tr>
- <td align="left" valign="top">
- <programlisting>rule “increase balance for AccountPeriod Credits”
-when
- ap : AccountPeriod()
- acc : Account( $accountNo : accountNo )
- CashFlow( type == CREDIT,
- accountNo == $accountNo,
- 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
- ap : AccountPeriod()
- acc : Account( $accountNo : accountNo )
- CashFlow( type == DEBIT,
- accountNo == $accountNo,
- date >= ap.start && <= ap.end,
- $ammount : ammount )
-then
- acc.balance -= $amount;
-end</programlisting>
- </td>
- </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="0">
- <tbody>
- <tr>
- <td align="left" valign="top">
- <table border="1" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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>
- </table>
- </td>
- </tr>
- </tbody>
- </table>
-
- <table border="0">
- <tbody>
- <tr>
- <td align="left" valign="top">
- <table border="1" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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>
- </table>
- </td>
- </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="0">
- <tbody>
- <tr>
- <td align="left" valign="top">
- <table border="1" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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>
- </table>
- </td>
- </tr>
- </tbody>
- </table>
-
- <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" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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>
- </table>
- </td>
- </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="0">
- <tbody>
- <tr>
- <td align="left" valign="top">
- <table border="1" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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>
- </table>
- </td>
- </tr>
- </tbody>
- </table>
-
- <table border="0">
- <tbody>
- <tr>
- <td align="left" valign="top">
- <table border="1" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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 />
- </tr>
- </tbody>
- </table>
- </td>
- </tr>
- </tbody>
- </table>
-
- <para>The firing of that Activation results in a balance of 50.</para>
-
- <table border="0">
- <tbody>
- <tr>
- <td align="left" valign="top">
- <table border="1" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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>
- </table>
- </td>
- </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="0">
- <tbody>
- <tr>
- <td>
- <programlisting>rule “Print blance for AccountPeriod”
- salience -50
- when
- ap : AccountPeriod()
- acc : Account( )
- then
- System.out.println( acc.accountNo + “ : “ acc.balance );
-end</programlisting>
- </td>
- </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="0">
- <tbody>
- <tr>
- <td align="left" valign="top">
- <table border="1" ccellspacing="0" cellpadding="3"
- style="border-style:solid; border-spacing:0; border-collapse:collapse">
- <thead>
- <tr>
- <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 />
- </tr>
- </tbody>
- </table>
- </td>
- </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="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.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.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>
-
- <mediaobject>
- <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="0">
- <tbody>
- <tr>
- <td align="left" valign="top">
- <programlisting>rule “increase balance for AccountPeriod Credits”
- ruleflow-group “calculation”
-when
- ap : AccountPeriod()
- acc : Account( $accountNo : accountNo )
- CashFlow( type == CREDIT,
- accountNo == $accountNo,
- 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”
- when
- ap : AccountPeriod()
- acc : Account( )
- then
- System.out.println( acc.accountNo + “ : “ acc.balance );
-end</programlisting>
- </td>
- </tr>
- </tbody>
- </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>
+ <xi:include href="Section-The_Basics.xml" />
+ <xi:include href="Section-A_Little_More_Theory.xml" />
+ <xi:include href="Section-More_On_Building_And_Deploying.xml" />
+
</chapter>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-A_Little_More_Theory.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-A_Little_More_Theory.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-A_Little_More_Theory.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,407 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
+
+
+ <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>
+
+ <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>
+ </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>
+
+ <programlisting>rule
+when
+ $room : Room()
+ $sprinkler : Sprinkler()
+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>
+
+ <programlisting>room:office sprinker:office
+room:office sprinker:kitchen
+room:office sprinker:livingroom
+room:office sprinker:bedroom
+room:kitchen sprinker:office
+room:kitchen sprinker:kitchen
+room:kitchen sprinker:livingroom
+room:kitchen sprinker:bedroom
+room:livingroom sprinker:office
+room:livingroom sprinker:kitchen
+room:livingroom sprinker:livingroom
+room:livingroom sprinker:bedroom
+room:bedroom sprinker:office
+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>
+
+ <programlisting>rule
+when
+ $room : Room()
+ $sprinkler : Sprinkler( room == $room )
+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>
+
+ <programlisting>room:office sprinker:office
+room:kitchen sprinker:kitchen
+room:livingroom sprinker:livingroom
+room:bedroom sprinker:bedroom</programlisting>
+ </section>
+
+ <section>
+ <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;
+ private int type;
+ long accountNo;
+ // getter and setter methods here
+}
+
+public class Account {
+ private long accountNo;
+ private double balance;
+ // getter and setter methods here
+}
+
+public AccountPeriod {
+ private Date start;
+ 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>
+
+ <figure>
+ <title>CashFlows and Account</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Quick_Start/tables1.png" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <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>
+ <td align="left" valign="top">
+ <programlisting>rule "increase balance for AccountPeriod Credits"
+when
+ ap : AccountPeriod()
+ acc : Account( $accountNo : accountNo )
+ CashFlow( type == CREDIT,
+ accountNo == $accountNo,
+ 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
+ ap : AccountPeriod()
+ acc : Account( $accountNo : accountNo )
+ CashFlow( type == DEBIT,
+ accountNo == $accountNo,
+ date >= ap.start && <= ap.end,
+ $ammount : ammount )
+then
+ acc.balance -= $amount;
+end</programlisting>
+ </td>
+ </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>
+
+ <figure>
+ <title>CashFlows and Account</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Quick_Start/tables2.png" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <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>
+
+ <figure>
+ <title>CashFlows and Account</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Quick_Start/tables7.png" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>After each of the above activations are fired, the Account has a
+ balance of -25.</para>
+
+ <figure>
+ <title>CashFlows and Account</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Quick_Start/tables3.png" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <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>
+
+ <figure>
+ <title>CashFlows and Account</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Quick_Start/tables4.png" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The firing of that Activation results in a balance of 25.</para>
+
+ <figure>
+ <title>CashFlows and Account</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Quick_Start/tables5.png" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <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>
+ <programlisting>rule "Print blance for AccountPeriod"
+ salience -50
+ when
+ ap : AccountPeriod()
+ acc : Account( )
+ then
+ System.out.println( acc.accountNo + " : " acc.balance );
+end</programlisting>
+ </td>
+ </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>
+
+ <figure>
+ <title>CashFlows and Account</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-Quick_Start/tables6.png" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <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.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.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>
+
+ <mediaobject>
+ <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="0">
+ <tbody>
+ <tr>
+ <td align="left" valign="top">
+ <programlisting>rule "increase balance for AccountPeriod Credits"
+ ruleflow-group "calculation"
+when
+ ap : AccountPeriod()
+ acc : Account( $accountNo : accountNo )
+ CashFlow( type == CREDIT,
+ accountNo == $accountNo,
+ 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"
+ when
+ ap : AccountPeriod()
+ acc : Account( )
+ then
+ System.out.println( acc.accountNo + " : " acc.balance );
+end</programlisting>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </section>
+
+
+
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-More_On_Building_And_Deploying.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-More_On_Building_And_Deploying.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-More_On_Building_And_Deploying.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
+
+ <title>More on building and deploying</title>
+
+
+ <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>
Modified: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-The_Basics.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-The_Basics.xml 2009-04-16 11:50:03 UTC (rev 26060)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Quick_Start/Section-The_Basics.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -1,6 +1,469 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE section PUBLIC "-//OASIS//DTD Simplified DocBook XML V1.0//EN"
-"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd">
-<section>
- <title>The Basics</title>
-</section>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
+
+ <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>
+
+ <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>
+ </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>
+
+ <programlisting>public class Applicant {
+ private String name;
+ private int age;
+ private boolean valid;
+ // 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>
+
+ <programlisting>package com.company.license
+
+rule "Is of valid age"
+when
+ $a : Applicant( age < 18 )
+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>
+
+ <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>
+
+ <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>
+
+ <programlisting>public class Applicant {
+ private String name;
+ private int age;
+ // getter and setter methods here
+}
+
+
+public class Application {
+ private Date dateApplied;
+ 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>
+
+ <programlisting>package com.company.license
+
+rule "Is of valid age"
+when
+ Applicant( age < 18 )
+ $a : Application()
+then
+ $a.setValid( false );
+end
+
+rule "Application was made this year"
+when
+ $a : Application( dateApplied > "01-jan-2009" )
+then
+ $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>
+
+ <programlisting>StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
+Applicant applicant = new Applicant( "Mr John Smith", 16 );
+Application application = new Application();
+assertTrue( application() );
+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).</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>
+
+ <itemizedlist>
+ <listitem>
+ <para>Monitoring</para>
+
+ <itemizedlist>
+ <listitem>
+ <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>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+
+ <para>Unlike a stateless session the dispose() method must be called
+ afterwards to ensure there are no memory leaks, as the KnowledgeBase
+ contains 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
+}
+public classs Sprinkler {
+ private Room room;
+ private boolean on;
+ // getter and setter methods here
+}
+public class Fire {
+ private Room room;
+ // getter and setter methods here
+}
+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>
+
+ <programlisting>rule "When there is a fire turn on the sprinkler"
+when
+ Fire($room : room)
+ $sprinkler : Sprinkler( room == $room, on == false )
+then
+ modify( $sprinkler ) { setOn( true ) };
+ System.out.println( "Turn on 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 typically do not use inference, which
+ can be explicitly turned off by using the "sequential mode", 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 off the sprinkler"
+when
+ $room : Room( )
+ $sprinkler : Sprinkler( room == $room, on == true )
+ not Fire( room == $room )
+then
+ 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>
+
+ <programlisting>rule "Raise the alarm when we have one or more fires"
+when
+ exists Fire()
+then
+ 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>
+
+ <programlisting>rule "Lower the alarm when all the fires have gone"
+when
+ not Fire()
+ $alarm : Alarm()
+then
+ retract( $alarm );
+ System.out.println( "Lower the alarm" );
+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>
+
+ <programlisting>rule "Status output when things are ok"
+when
+ not Alarm()
+ not Sprinkler( on === true )
+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>
+
+ <programlisting>KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+kbuilder.add( ResourceFactory.newClasspathResource( "fireAlarm.drl", getClass() ),
+ ResourceType.DRL );
+if ( kbuilder.hasErrors() ) {
+ 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>
+
+ <programlisting>Room kitchen = new Room( "kitchen" );
+Room bedroom = new Room( "bedroom" );
+Room office = new Room( "office" );
+Room livingRoom = new Room( "livingroom" );
+
+ksession.insert( kitchen );
+ksession.insert( bedroom );
+ksession.insert( office );
+ksession.insert( livingRoom );
+
+Sprinkler kitchenSprinkler = new Sprinkler( kitchen );
+Sprinkler bedroomSprinkler = new Sprinkler( bedroom );
+Sprinkler officeSprinkler = new Sprinkler( office );
+Sprinkler livingRoomSprinkler = new Sprinkler( livingRoom );
+
+
+ksession.insert( kitchenSprinkler );
+ksession.insert( bedroomSprinkler );
+ksession.insert( officeSprinkler );
+ksession.insert( livingRoomSprinkler );
+
+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>
+
+ <programlisting>Fire kitchenFire = new Fire( kitchen );
+Fire officeFire = new Fire( office );
+
+FactHandle kitchenFireHandle = ksession.insert( kitchenFire );
+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>
+
+ <programlisting>ksession.retract( kitchenFireHandle );
+ksession.retract( officeFireHandle );
+
+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>
+ </section>
+
+</section>
Modified: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Chapter-Rule_Engine.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Chapter-Rule_Engine.xml 2009-04-16 11:50:03 UTC (rev 26060)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Chapter-Rule_Engine.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -9,12 +9,12 @@
<xi:include href="Section-Why_use_a_Rule_Engine.xml" />
- <xi:include href="Section-Rules.xml" />
+ <!--xi:include href="Section-Rules.xml" />
- <xi:include href="Section-Rete_Algorithm.xml" />
-
- <xi:include href="Section-The_Drools_Rule_Engine.xml" />
-
+ <xi:include href="Section-Rete_Algorithm.xml" /-->
+
+ <!--xi:include href="Section-The_Drools_Rule_Engine.xml" /-->
+
<!--xi:include href="Chapter-Rule_Engine/Section-Rule_Base.xml" />
<xi:include href="Chapter-Rule_Engine/Section-Working_Memory.xml" />
Modified: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Section-Rules.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Section-Rules.xml 2009-04-16 11:50:03 UTC (rev 26060)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Section-Rules.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<section 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"
- xmlns:db="http://docbook.org/ns/docbook" xml:base="../../">
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
<title>Knowledge Representation</title>
<!--section>
@@ -216,9 +216,9 @@
system.</para>
<para>A proposition is a statement that can be classified as true or
- false. If the truth can be determined from the statement alone it is said to
- be a "closed statement". In programming terms this is an expression that
- does not reference any variables:</para>
+ false. If the truth can be determined from the statement alone it is said
+ to be a "closed statement". In programming terms this is an expression
+ that does not reference any variables:</para>
<programlisting>10 == 2 * 5</programlisting>
@@ -228,8 +228,8 @@
<programlisting>Person.sex == "male"</programlisting>
- <para>With SQL, the conclusion's action is to return
- the matched fact to the user:</para>
+ <para>With SQL, the conclusion's action is to return the matched fact to
+ the user:</para>
<programlisting>select * from Person where Person.sex == "male"</programlisting>
@@ -243,18 +243,21 @@
<mediaobject>
<imageobject>
- <imagedata align="center" fileref="images/Chapter-Rule_Engine/Male_Person.svg" format="SVG" contentwidth="485px" contentdepth="213px" />
+ <imagedata align="center" contentdepth="213px" contentwidth="485px"
+ fileref="images/Chapter-Rule_Engine/Male_Person.png"
+ format="PNG"></imagedata>
</imageobject>
</mediaobject>
</figure>
<para>In Java we can write simple proposition as a boolean expression
- 'variable' 'operator' 'value', where 'value' frequently is a
- literal value, and such a proposition can be thought of as a field constraint.
+ 'variable' 'operator' 'value', where 'value' frequently is a literal
+ value, and such a proposition can be thought of as a field constraint.
Furthermore, such a proposition can be combined with conjunctive and
disjunctive connectives, which is the logic theorists' denomination for
- '&&' and '||'. The following expression shows two open propositional
- statements connected with a single disjunctive connective.</para>
+ '&&' and '||'. The following expression shows two open
+ propositional statements connected with a single disjunctive
+ connective.</para>
<programlisting role="JAVA">person.getEyeColor().equals("blue") || person.getEyeColor().equals("green")</programlisting>
@@ -275,10 +278,10 @@
Logic with two quantifier concepts to allow expressions defining
structure, i.e., the universal and existential quantifiers. Universal
quantifiers allow you to check that something is true for everything,
- normally supported by the <code>forall</code> conditional element. Existential
- quantifiers check for the existence of something, in that it occurs at
- least once, this being supported with <code>not</code> and <code>exists</code> conditional
- elements.</para>
+ normally supported by the <code>forall</code> conditional element.
+ Existential quantifiers check for the existence of something, in that it
+ occurs at least once, this being supported with <code>not</code> and
+ <code>exists</code> conditional elements.</para>
<para>Imagine we have two classes: Student and Module. Module represents
each of the courses the Student attended for that semester, referenced by
@@ -288,11 +291,11 @@
40" open proposition to check for the existence of a Module that is true
for the specified criteria.</para>
- <programlisting role="JAVA"><![CDATA[public class Student {
+ <programlisting role="JAVA">public class Student {
private String name;
- private List<Module> modules;
+ private List&lt;Module&gt; modules;
...
- }]]></programlisting>
+ }</programlisting>
<programlisting role="JAVA">
public class Module {
@@ -323,8 +326,8 @@
<para>Early SQL implementations were not Turing complete as they did not
provide quantifiers to access the structure of data. Modern SQL engines do
allow nesting of SQL, which can be combined with keywords like 'exists'
- and 'in'. The following snippets show SQL to return a set of students
- who have failed the semester, and a rule firing for such students.</para>
+ and 'in'. The following snippets show SQL to return a set of students who
+ have failed the semester, and a rule firing for such students.</para>
<programlisting role="SQL">
select
Modified: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Section-What_is_a_Rule_Engine.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Section-What_is_a_Rule_Engine.xml 2009-04-16 11:50:03 UTC (rev 26060)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Rule_Engine/Section-What_is_a_Rule_Engine.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<section 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"
- xmlns:db="http://docbook.org/ns/docbook" xml:base="../../">
+<section 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:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:db="http://docbook.org/ns/docbook">
<title>What is a Rule Engine?</title>
<section>
@@ -26,18 +26,20 @@
MYCIN medical diagnosis Expert System. Whereas early Expert Systems had
their logic hard-coded, "shells" separated the logic from the system,
providing an easy to use environment for user input. Drools is a Rule
- Engine that uses the rule-based approach to implement an Expert System
- and is more correctly classified as a Production Rule System.</para>
+ Engine that uses the rule-based approach to implement an Expert System and
+ is more correctly classified as a Production Rule System.</para>
<para>The term "Production Rule" originates from formal grammars where it
is described as "an abstract structure that describes a formal language
precisely, i.e., a set of rules that mathematically delineates a (usually
infinite) set of finite-length strings over a (usually finite) alphabet"
- (<ulink url="http://en.wikipedia.org/wiki/Formal_grammar"><citetitle>wikipedia</citetitle></ulink>).</para>
+ (<ulink url="http://en.wikipedia.org/wiki/Formal_grammar">
+ <citetitle>wikipedia</citetitle>
+ </ulink>).</para>
<para>Business Rule Management Systems build additional value on top of a
- general purpose Rule Engine by providing business user focused systems
- for rule creation, management, deployment, collaboration, analysis and end
+ general purpose Rule Engine by providing business user focused systems for
+ rule creation, management, deployment, collaboration, analysis and end
user tools. Further adding to this value is the fast evolving and popular
methodology "Business Rules Approach", which is a helping to formalize the
role of Rule Engines in the enterprise.</para>
@@ -54,25 +56,26 @@
subtleties of Rules Engines' differences, who was hoping to find some
hidden secrets to help improve the Drools engine. JBoss jBPM uses
expressions and delegates in its Decision nodes which control the
- transitions in a Workflow. At each node it evaluates ther is a rule set that
- dictates the transition to undertake, and so this is also a Rule Engine. While a
- Production Rule System is a kind of Rule Engine and also an Expert System,
- the validation and expression evaluation Rule Engines mentioned previously
- are not Expert Systems.</para>
+ transitions in a Workflow. At each node it evaluates ther is a rule set
+ that dictates the transition to undertake, and so this is also a Rule
+ Engine. While a Production Rule System is a kind of Rule Engine and also
+ an Expert System, the validation and expression evaluation Rule Engines
+ mentioned previously are not Expert Systems.</para>
<para>A Production Rule System is Turing complete, with a focus on
knowledge representation to express propositional and first order logic in
a concise, non-ambiguous and declarative manner. The brain of a Production
Rules System is an Inference Engine that is able to scale to a large
number of rules and facts. The Inference Engine matches facts and data
- against Production Rules - also called Productions or just Rules - to infer
- conclusions which result in actions. A Production Rule is a two-part
- structure using First Order Logic for reasoning over knowledge representation.</para>
+ against Production Rules - also called Productions or just Rules - to
+ infer conclusions which result in actions. A Production Rule is a two-part
+ structure using First Order Logic for reasoning over knowledge
+ representation.</para>
- <programlisting role="JAVA"><![CDATA[when
- <conditions>
+ <programlisting role="JAVA">when
+ <conditions>
then
- <actions>;]]></programlisting>
+ <actions>;</programlisting>
<para>The process of matching the new or existing facts against Production
Rules is called <indexterm>
@@ -102,20 +105,17 @@
<para>Drools implements and extends the <indexterm>
<primary>Rete</primary>
- </indexterm> Rete algorithm;<indexterm>
+ </indexterm> Rete algorithm;<indexterm>
<primary>Leaps</primary>
- </indexterm> Leaps used to be provided but was retired as it became unmaintained. The Drools <indexterm>
+ </indexterm> Leaps used to be provided but was retired as it became
+ unmaintained. The Drools <indexterm>
<primary>Rete</primary>
</indexterm> Rete implementation is called ReteOO, signifying that
Drools has an enhanced and optimized implementation of the Rete algorithm
for object oriented systems. Other Rete based engines also have marketing
terms for their proprietary enhancements to Rete, like RetePlus and Rete
- III. It is important to understand that names like Rete III are purely
- marketing oriented where, unlike the original published Rete Algorithm, no details
- of the implementation are published. This makes questions such as "Does
- Drools implement Rete III?" nonsensical. The most common enhancements are
- covered in "Production Matching for Large Learning Systems (Rete/UL)"
- (1995) by Robert B. Doorenbos.</para>
+ III. The most common enhancements are covered in "Production Matching for
+ Large Learning Systems (Rete/UL)" (1995) by Robert B. Doorenbos.</para>
<para>The Rules are stored in the <indexterm>
<primary>Production Memory</primary>
@@ -131,75 +131,54 @@
<figure>
<title>High-level View of a Rule Engine</title>
+
<mediaobject>
<imageobject>
- <imagedata align="center" fileref="images/Chapter-Rule_Engine/rule-engine-inkscape.svg" format="SVG" contentwidth="540px" contentdepth="300px" />
+ <imagedata align="center" contentdepth="300px" contentwidth="540px"
+ fileref="images/Chapter-Rule_Engine/rule-engine-inkscape.png"
+ format="PNG"></imagedata>
</imageobject>
- </mediaobject>
+ </mediaobject>
</figure>
- <para>A Production Rule System's Inference Engine is stateful and able to
- enforce truthfulness, which is called Truth Maintenance. A logical relationship can
- be declared by actions which means the action's state depends on the
- inference remaining true; when it is no longer true the logically dependent
- action is undone. The "Honest Politician" is an example of Truth
- Maintenance, which always ensures that hope can only exist for a
- democracy while we have honest politicians.</para>
+ <para>There are two methods of execution for a rule system: Forward
+ Chaining and Backward Chaining; systems that implement both are called
+ Hybrid Rule Systems. Understanding these two modes of operation is the key
+ to understanding why a Production Rule System is different and how to get
+ the best from it. Forward chaining is "data-driven" and thus reactionary,
+ with facts being asserted into working memory, which results in one or
+ more rules being concurrently true and scheduled for execution by the
+ Agenda. In short, we start with a fact, it propagates and we end in a
+ conclusion. Drools is a forward chaining engine.</para>
- <programlisting role="JAVA">
-when
- an honest Politician exists
-then
- logically assert Hope
-
-when
- Hope exists
-then
- print "Hurrah!!! Democracy Lives"
-
-when
- Hope does not exist
-then
- print "Democracy is Doomed"
-</programlisting>
-
- <para>There are two methods of execution for a Production Rule Systems:
- Forward Chaining and Backward Chaining; systems that implement both are
- called Hybrid Production Rule Systems. Understanding these two modes of
- operation is the key to understanding why a Production Rule System is
- different and how to get the best from it. Forward chaining is
- "data-driven" and thus reactionary, with facts being asserted into working
- memory, which results in one or more rules being concurrently true and
- scheduled for execution by the Agenda. In short, we start with a fact, it
- propagates and we end in a conclusion. Drools is a forward chaining
- engine.</para>
-
<figure>
<title>Forward Chaining</title>
<mediaobject>
<imageobject>
- <imagedata align="center" fileref="images/Chapter-Rule_Engine/Forward_Chaining.png"
- format="PNG" />
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Forward_Chaining.png"
+ format="PNG"></imagedata>
</imageobject>
</mediaobject>
</figure>
<para>Backward chaining is "goal-driven", meaning that we start with a
conclusion which the engine tries to satisfy. If it can't it then searches
- for conclusions that it can satisfy; these are known as subgoals, that will help satisfy
- some unknown part of the current goal. It continues this process until
- either the initial conclusion is proven or there are no more subgoals.
- Prolog is an example of a Backward Chaining engine; Drools will provide
- support for Backward Chaining in its next major release.</para>
+ for conclusions that it can satisfy; these are known as subgoals, that
+ will help satisfy some unknown part of the current goal. It continues this
+ process until either the initial conclusion is proven or there are no more
+ subgoals. Prolog is an example of a Backward Chaining engine; Drools plans
+ to provide support for Backward Chaining in a future release.</para>
<figure>
<title>Backward Chaining</title>
<mediaobject>
<imageobject>
- <imagedata align="center" fileref="images/Chapter-Rule_Engine/Backward_Chaining.png"
- format="PNG" />
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Backward_Chaining.png"
+ format="PNG"></imagedata>
</imageobject>
</mediaobject>
</figure>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Theory/Chapter-Theory.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Theory/Chapter-Theory.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Theory/Chapter-Theory.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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>Advanced Concepts and Theory</title>
+
+ <section>
+ <title>Truth Maintenance with <indexterm>
+ <primary>Logical Object</primary>
+ </indexterm> Logical Objects</title>
+
+ <para>After regular inserts you have to retract facts explicitly. With
+ <emphasis>logical</emphasis> assertions, the fact that was asserted will
+ be automatically retracted when the conditions that asserted it in the
+ first place are no longer true. Actually, it's even cleverer then that,
+ because it will be retracted only if there isn't any single condition that
+ supports the logical assertion.</para>
+
+ <para>Normal insertions are said to be <emphasis>stated</emphasis>, i.e.,
+ just like the intuitive meaning of "stating a fact" implies. Using a
+ <code>HashMap</code> and a counter, we track how many times a particular
+ equality is <emphasis>stated</emphasis>; this means we count how many
+ different instances are equal.</para>
+
+ <para>When we <emphasis>logically</emphasis> insert an object during a RHS
+ execution we are said to <emphasis>justify</emphasis> it, and it is
+ considered to be justified by the firing rule. For each logical insertion
+ there can only be one equal object, and each subsequent equal logical
+ insertion increases the justification counter for this logical assertion.
+ A justification is removed by the LHS of the creating rule becoming
+ untrue, and the counter is decreased accordingly. As soon as we have no
+ more justifications the logical object is automatically retracted.</para>
+
+ <para>If we try to <emphasis>logically</emphasis> insert an object when
+ there is an equal <emphasis>stated</emphasis> object, this will fail and
+ return null. If we <emphasis>state</emphasis> an object that has an
+ existing equal object that is <emphasis>justified</emphasis> we override
+ the Fact; how this override works depends on the configuration setting
+ <code>WM_BEHAVIOR_PRESERVE</code>. When the property is set to discard we
+ use the existing handle and replace the existing instance with the new
+ Object, which is the default behavior; otherwise we override it to
+ <emphasis>stated</emphasis> but we create an new
+ <code>FactHandle</code>.</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 <code>FactHandle</code>,
+ this also indicates the <code>Object</code> was propagated through the
+ network. <figure>
+ <title>Stated Insertion</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Stated_Assertion.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure> <figure>
+ <title>Logical Insertion</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Logical_Assertion.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure></para>
+
+ <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 account
+ transaction. The rule engine is doing its best to decide whether
+ transactions are possibly fraudulent or not. Imagine that 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>Then there can be a series of rules whose job is to look for
+ things that may raise suspicion, and if they fire, they
+ <emphasis>logically</emphasis> insert 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. After all
+ the facts causing the SuspiciousAccount() insertion are removed, the
+ account handling reverts to a normal mode of operation where, for
+ instance, a rule with "not SuspiciousAccount()" may kick in, which
+ flushes through any blocked 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
+ manageable.</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)
+ must override equals and hashCode methods (from java.lang.Object)
+ correctly. As the truth maintenance system needs to know when two
+ different physical objects are equal in value, <emphasis>both</emphasis>
+ 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
+ <emphasis>MUST</emphasis> override both equals and hashCode).</para>
+ </section>
+ </section>
+
+ <section xml:base="">
+ <title>Rete Algorithm</title>
+
+ <para>The <emphasis>Rete</emphasis> algorithm was invented by Dr. Charles
+ Forgy and documented in his PhD thesis in 1978-79. A simplified version of
+ the paper was published in 1982 (<ulink
+ url="http://citeseer.ist.psu.edu/context/505087/0">http://citeseer.ist.psu.edu/context/505087/0</ulink>).
+ The latin word "rete" means "net" or "network". The Rete algorithm can be
+ broken into 2 parts: rule compilation and runtime execution.</para>
+
+ <para>The compilation algorithm describes how the Rules in the Production
+ Memory are processed to generate an efficient discrimination network. In
+ non-technical terms, a discrimination network is used to filter data as it
+ propagates through the network. The nodes at the top of the network would
+ have many matches, and as we go down the network, there would be fewer
+ matches. At the very bottom of the network are the terminal nodes. In Dr.
+ Forgy's 1982 paper, he described 4 basic nodes: root, 1-input, 2-input and
+ terminal.</para>
+
+ <figure>
+ <title>Rete Nodes</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center" contentdepth="244" contentwidth="392"
+ fileref="images/Chapter-Rule_Engine/Rete_Nodes.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The root node is where all objects enter the network. From there, it
+ immediately goes to the ObjectTypeNode. The purpose of the ObjectTypeNode
+ is to make sure the engine doesn't do more work than it needs to. For
+ example, say we have 2 objects: Account and Order. If the rule engine
+ tried to evaluate every single node against every object, it would waste a
+ lot of cycles. To make things efficient, the engine should only pass the
+ object to the nodes that match the object type. The easiest way to do this
+ is to create an ObjectTypeNode and have all 1-input and 2-input nodes
+ descend from it. This way, if an application asserts a new Account, it
+ won't propagate to the nodes for the Order object. In Drools when an
+ object is asserted it retrieves a list of valid ObjectTypesNodes via a
+ lookup in a HashMap from the object's Class; if this list doesn't exist it
+ scans all the ObjectTypeNodes finding valid matches which it caches in the
+ list. This enables Drools to match against any Class type that matches
+ with an <literal>instanceof</literal> check.</para>
+
+ <figure>
+ <title>ObjectTypeNodes</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Object_Type_Nodes.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>ObjectTypeNodes can propagate to AlphaNodes, LeftInputAdapterNodes
+ and BetaNodes. AlphaNodes are used to evaluate literal conditions.
+ Although the 1982 paper only covers equality conditions, many RETE
+ implementations support other operations. For example, <code>Account.name
+ == "Mr Trout"</code> is a literal condition. When a rule has multiple
+ literal conditions for a single object type, they are linked together.
+ This means that if an application asserts an Account object, it must first
+ satisfy the first literal condition before it can proceed to the next
+ AlphaNode. In Dr. Forgy's paper, he refers to these as IntraElement
+ conditions. The following diagram shows the AlphaNode combinations for
+ Cheese( name == "cheddar", strength == "strong" ):</para>
+
+ <figure>
+ <title>AlphaNodes</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Alpha_Nodes.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Drools extends Rete by optimizing the propagation from
+ ObjectTypeNode to AlphaNode using hashing. Each time an AlphaNode is added
+ to an ObjectTypeNode it adds the literal value as a key to the HashMap
+ with the AlphaNode as the value. When a new instance enters the ObjectType
+ node, rather than propagating to each AlphaNode, it can instead retrieve
+ the correct AlphaNode from the HashMap,thereby avoiding unnecessary
+ literal checks.</para>
+
+ <para>There are two two-input nodes, JoinNode and NotNode, and both are
+ types of BetaNodes. BetaNodes are used to compare 2 objects, and their
+ fields, to each other. The objects may be the same or different types. By
+ convention we refer to the two inputs as left and right. The left input
+ for a BetaNode is generally a list of objects; in Drools this is a Tuple.
+ The right input is a single object. Two Nodes can be used to implement
+ 'exists' checks. BetaNodes also have memory. The left input is called the
+ Beta Memory and remembers all incoming tuples. The right input is called
+ the Alpha Memory and remembers all incoming objects. Drools extends Rete
+ by performing indexing on the BetaNodes. For instance, if we know that a
+ BetaNode is performing a check on a String field, as each object enters we
+ can do a hash lookup on that String value. This means when facts enter
+ from the opposite side, instead of iterating over all the facts to find
+ valid joins, we do a lookup returning potentially valid candidates. At any
+ point a valid join is found the Tuple is joined with the Object; which is
+ referred to as a partial match; and then propagated to the next
+ node.</para>
+
+ <figure>
+ <title>JoinNode</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Join_Node.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>To enable the first Object, in the above case Cheese, to enter the
+ network we use a LeftInputNodeAdapter - this takes an Object as an input
+ and propagates a single Object Tuple.</para>
+
+ <para>Terminal nodes are used to indicate a single rule having matched all
+ its conditions; at this point we say the rule has a full match. A rule
+ with an 'or' conditional disjunctive connective results in subrule
+ generation for each possible logically branch; thus one rule can have
+ multiple terminal nodes.</para>
+
+ <para>Drools also performs node sharing. Many rules repeat the same
+ patterns, and node sharing allows us to collapse those patterns so that
+ they don't have to be re-evaluated for every single instance. The
+ following two rules share the first pattern, but not the last:</para>
+
+ <programlisting>
+
+ rule
+ when
+ Cheese( $chedddar : name == "cheddar" )
+ $person : Person( favouriteCheese == $cheddar )
+ then
+ System.out.println( $person.getName() + " likes cheddar" );
+ end
+
+ </programlisting>
+
+ <programlisting>
+
+ rule
+ when
+ Cheese( $chedddar : name == "cheddar" )
+ $person : Person( favouriteCheese != $cheddar )
+ then
+ System.out.println( $person.getName() + " does not like cheddar" );
+ end
+
+ </programlisting>
+
+ <para>As you can see below, the compiled Rete network shows that the alpha
+ node is shared, but the beta nodes are not. Each beta node has its own
+ TerminalNode. Had the second pattern been the same it would have also been
+ shared.</para>
+
+ <figure>
+ <title>Node Sharing</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Node_Sharing.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </section>
+</chapter>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Chapter-User_Guide.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Chapter-User_Guide.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Chapter-User_Guide.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,16 @@
+<?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:ns="http://docbook.org/ns/docbook"
+ xmlns:m="http://www.w3.org/1998/Math/MathML"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+ <title>User Guide</title>
+
+ <xi:include href="Section-Building.xml" />
+
+ <xi:include href="Section-Deploying.xml" />
+
+ <xi:include href="Section-Running.xml" />
+</chapter>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Building.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Building.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Building.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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>Building</title>
+
+ <figure>
+ <title>org.drools.builder</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/builder.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <section>
+ <title>Building using Code</title>
+
+ <para>The KnowledgeBuilder is responsible for taking source files, such as
+ a .drl file or an xls file, and turning them into a KnowledgePackage of
+ rule and process definitions which a KnowledgeBase can consume. It uses
+ the ResourceType enum to tell it the type of the resource it is being
+ asked to build.</para>
+
+ <para>The ResourceFactory provides capabilities to load Resources from a
+ number of sources; such as Reader, ClassPath, URL, File, ByteArray.
+ Binaries, such as xls decision tables, should not use a Reader based
+ Resource handler, which is only suitable for text based resource</para>
+
+ <figure>
+ <title>KnowledgeBuilder</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgeBuilder.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The KnowlegeBuilder is created using the
+ KnowledgeBuilderFactory.</para>
+
+ <figure>
+ <title>KnowledgeBuilderFactory</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgeBuilderFactory.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>A KnowledgeBuilder can be created using the default
+ configuration.</para>
+
+ <example>
+ <title>Creating a new KnowledgeBuilder</title>
+
+ <programlisting>KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();</programlisting>
+ </example>
+
+ <para>A configuration can be created using the KnowledgeBuilderFactory
+ this allows the behaviour of the KnowledgeBuilder to modified. The most
+ common usage is to provide a custom ClassLoader so that the kbuilder can
+ resolve classes that are not in the default classpath. The first parameter
+ is for Properties and is optional and may be left null in which case the
+ default options will be used. The options parameter can be used for things
+ like changing the dialect or registering new accumulator functions.</para>
+
+ <example>
+ <title>Creating a new KnowledgeBuilder with a custom ClassLoader</title>
+
+ <programlisting>KnowledgeBuilderConfiguration kbuilderConf = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(null, classLoader );
+KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(kbuilderConf);
+</programlisting>
+ </example>
+
+ <para>Resources, of any type, can be add iteratively. Below a DRL is
+ added. Unlike Drools 4.0 PackageBuilder the KnowledgeBuilder can now
+ handle multiple namespaces, so you can just keep adding resources
+ regardless of namespace.</para>
+
+ <example>
+ <title>Adding DRL Resources</title>
+
+ <programlisting>kbuilder.add( ResourceFactory.newFileResource( "/project/myrules.drl" ),
+ ResourceType.DRL);
+</programlisting>
+ </example>
+
+ <para>It is best practice to always check the hasErrors() method after an
+ addition, you should not add more resources or get the KnowledgePackages
+ if there are errors. KnowledgePackages() will return an empty list if
+ there are errors.</para>
+
+ <example>
+ <title>Validating</title>
+
+ <programlisting>if( kbuilder.hasErrors() ) {
+ System.out.println( kbuilder.getErrors() );
+ return;
+}
+</programlisting>
+ </example>
+
+ <para>When all the resources has been added and there are no errors the
+ Collection of KnowledgePackages can be retrieved, it's a Collection as
+ there is one KnowledgePackage per package namespace; These
+ KnowledgePackages are serialisable and often used as a unit of
+ deployment.</para>
+
+ <example>
+ <title>Getting the KnowledgePackages</title>
+
+ <programlisting>Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages();
+</programlisting>
+ </example>
+
+ <para>The final examples puts it all together.</para>
+
+ <example>
+ <title>Putting it together</title>
+
+ <programlisting>KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+if( kbuilder.hasErrors() ) {
+ System.out.println( kbuilder.getErrors() );
+ return;
+}
+
+KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+kbuilder.add( ResourceFactory.newFileResource( "/project/myrules1.drl" ),
+ ResourceType.DRL);
+kbuilder.add( ResourceFactory.newFileResource( "/project/myrules2.drl" ),
+ ResourceType.DRL);
+
+if( kbuilder.hasErrors() ) {
+ System.out.println( kbuilder.getErrors() );
+ return;
+}
+
+Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages();
+</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>Building using Configuration and the ChangeSet XML</title>
+
+ <para>Instead of adding the resources to create definitions
+ programmatically it is also possible to do it confiugrably via the
+ ChangeSet XML. There is currently no XSD schema for the change-set, but we
+ hope to add one soon. However the XML is very simple. The XML supports
+ three elements add, remove, modify - however currently only the add
+ element is supported - the later will be supprted as we eventually move to
+ support iterative changes. The following example loads a single DRL
+ file.</para>
+
+ <example>
+ <title>Simple ChangeSet XML</title>
+
+ <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:/project/myrules.drl' type='DRL' />
+ </add>
+</change-set>
+</programlisting>
+ </example>
+
+ <para>Notice the "file:" prefix, this signifies the protocol for the
+ resource. The ChangeSet 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. While using the
+ ClassPath resource loader in java allows you to specify the ClassLoader to
+ be used to locate the resource, from the XML this is not possible. Instead
+ the ClassLoader will default to the one used by the KnowledgeBuilder
+ unless the ChangeSet XML is itself loaded by the ClassPath resource, in
+ which case it'll use the ClassLoader specified for that resource.</para>
+
+ <para>You currently still need to use the API to load that ChangeSet, but
+ we will add support for containers such as Spring in the future, so the
+ process of creating a KnowledgeBase becomes 100% XML configuration.
+ Loading resources using the XML couldn't be simpler, as it's just another
+ ResourceType.</para>
+
+ <example>
+ <title>Loading the ChangeSet XML</title>
+
+ <programlisting>kbuilder.add( ResourceFactory.newUrlResource( url ), ResourceType.ChangeSet );
+</programlisting>
+ </example>
+
+ <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>
+
+ <example>
+ <title>ChangeSet XML with resource configuration</title>
+
+ <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>
+ </example>
+
+ <para>The ChangeSet is especailly useful when working with KnowledgeAgent,
+ as it allows for change notification and automatic rebuilding of the
+ KnowledgeBase, which is covered in more detail in the section on the
+ KnowledgeAgent under Deploying.</para>
+
+ <para>Directories can also be specified, in such a situation all resources
+ in that folder are added, although currently it expected all resources in
+ that folder to be of the same type. If you use the KnowledgeAgent it will
+ provide a continous scanning for added, modified or removed resources and
+ rebuild the cached KnowledgeBase. The KnowledgeAgent provides more
+ information on this.</para>
+
+ <example>
+ <title>ChangeSet XML which adds a directories contents</title>
+
+ <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:/projects/myproject/myrules' type='DRL' />
+ </add>
+</change-set>
+</programlisting>
+ </example>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Deploying.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Deploying.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Deploying.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,344 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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>Deploying</title>
+
+ <section>
+ <title>KnowledgePackage and Knowledge Definitions</title>
+
+ <para>The KnowledgePackage is a collection of Knowledge Definitions, such
+ as rules and processes, and is created by the KnowledgeBuilder, as seen in
+ The "Building" chapter. KnowledgePackages are self contained and
+ serializable and currently form the basic deployment unit.</para>
+
+ <figure>
+ <title>KnowledgePackage</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgePackage.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>KnowledgePackages are added to the KnowledgeBase. However a
+ KnowledgePackage instance cannot be re-used once it's added to the
+ KnowledgeBase, if you need to add it to another KnowledgeBase try
+ serialising it first and using the "cloned" result. We hope to fix this
+ limitation in future versions of Drools.</para>
+ </section>
+
+ <section>
+ <title>KnowledgeBase</title>
+
+ <para>The KnowlegeBase is a repository of all the application's knowledge
+ definitions. It may contain rules, processes, functions, type models. The
+ KnowledgeBase itself does not contain instance data, known as facts,
+ instead sessions are created from the KnowledgeBase in which data can be
+ inserted and process instances started. Creating the KnowlegeBase can be
+ heavy, where as session creation is very light, so it is recommended that
+ KnowleBase's be cached where possible to allow for repeated session
+ creation.</para>
+
+ <figure>
+ <title>KnowledgeBase</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgeBase.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The KnowledgeBase is also serializable and some people may prefer to
+ build and then store the KnowledgeBase, treating it also as a unit of
+ deployment, instead of the KnowledgePackages.</para>
+
+ <para>The KnowlegeBase is created using the KnowledgeBaseFactory.</para>
+
+ <figure>
+ <title>KnowledgeBaseFactory</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgeBaseFactory.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>A KnowledgeBase can be created using the default
+ configuration.</para>
+
+ <example>
+ <title>Creating a new KnowledgeBuilder</title>
+
+ <programlisting>KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();</programlisting>
+ </example>
+
+ <para>If a custom ClassLoader was used with the KnowledgeBuilder to
+ resolve types not in the default ClassLoader, then that must also be set
+ on the KnowledgeBuilder. The technique for this is the same as with the
+ KnowledgeBuilder.</para>
+
+ <example>
+ <title>Creating a new KnowledgeBase with a custom ClassLoader</title>
+
+ <programlisting>KnowledgeBaseConfiguration kbaseConf = KnowledgeBaseFactory.createKnowledgeBaseConfiguration( null, cl );
+KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase( kbaseConf );</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>In Process Building and Deployment</title>
+
+ <para>This is the simplest form of deployment and both compiles the
+ knowledge definitions and adds them to the KnowledgeBase in the same JVM.
+ This approach requires both drools-core and drools-compiler on the
+ classpath.</para>
+
+ <example>
+ <title>Add KnowledgePackages to a KnowledgeBase</title>
+
+ <programlisting>Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages();
+
+KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+kbase.addKnowledgePackages( kpkgs );</programlisting>
+ </example>
+
+ <para>Note the addKnowledgePackages( kpkgs ) method can be called
+ iteratively to add additional knowledge.</para>
+ </section>
+
+ <section>
+ <title>Out of Process Building and Deployment</title>
+
+ <para>Both the KnowledgeBase and the KnowledgePackage are units of
+ deployment and serializable. This means you can have one machine do any
+ necessary building, which requires drools-compiler, and have another
+ machine act as the runtime and only requiring drools-core.</para>
+
+ <para>While serialization is standard Java here is an example of how one
+ machine might write out the deployment unit and how another machine might
+ read in and use that deployment unit.</para>
+
+ <example>
+ <title>Writting the KnowledgePackage to an OutputStream</title>
+
+ <programlisting>ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream( fileName ) );
+out.writeObject( kpkgs );
+out.close();
+</programlisting>
+ </example>
+
+ <example>
+ <title>Reading the KnowledgePackage from an InputStream</title>
+
+ <programlisting>ObjectInputStream in = new ObjectInputStream( new FileInputStream( fileName ) );
+Collection<KnowledgePackages> kpkgs = in.readObject( ); // you could write an individual package or the Collection
+in.close();
+
+KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+kbase.addKnowledgePackages( kpkgs );
+</programlisting>
+
+ <para>The KnowledgeBase is also serializable and some people may prefer
+ to build and then store the KnowledgeBase itself, instead of the
+ KnowledgePackages.</para>
+
+ <para>Drools Guvnor, our server side management system, uses this
+ deployment approach. Where Guvnor will compile and publish serialized
+ KnowledgePackages on a URL and then Drools can use the URL resource type
+ to load it.</para>
+ </example>
+ </section>
+
+ <section>
+ <title>StatefulknowledgeSessions and KnowledgeBase modifications</title>
+
+ <para>StatefulKnowledgeSesions will be discussed in more details in the
+ Running section. The KnowledgeBase creates and returns
+ StatefulKnowledgeSesions and it may optionally keep references to those.
+ When KnowledgeBase modifications occur those modifications are applied
+ against the data in the sessions. This reference is weak reference and it
+ is also optional, which is controlled by a boolean flag.</para>
+ </section>
+
+ <section>
+ <title>KnowledgeAgent</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. 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</para>
+
+ <figure>
+ <title>KnowledgeAgent</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgeAgent.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The KnowlegeBuilder is created using the KnowledgeBuilderFactory.
+ The agent must specify a name, which is used in the logging to associate
+ the logging entry with the correct agent.</para>
+
+ <example>
+ <title>Creating the KnowledgeAgent</title>
+
+ <programlisting>KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" );
+</programlisting>
+ </example>
+
+ <figure>
+ <title>KnowledgeAgentFactory</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgeAgentFactory.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The Following example constructs an agent that will build a new
+ KnowledgeBase from specified ChangeSet, see the Building section for more
+ detail on the ChangeSet format. Note that the method can be called
+ iteratively to add new resources overtime. At the moment the remove and
+ modify elements of the ChangeSet XML do not work, but future versions will
+ enable this which means for more control over those incremental changes.
+ It will poll the resources added from in the ChangeSet every 60 seconds,
+ which is the default, to see if they are updated. If changes found it will
+ construct a new KnowledgeBase. If the change set specifies a resource that
+ is a directory it's contents will be scanned for changes to.</para>
+
+ <example>
+ <title>Writting the KnowledgePackage to an OutputStream</title>
+
+ <programlisting>KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" );
+kagent.applyChangeSet( ResourceFactory.newUrlResource( url ) );
+KnowledgeBase kbase = kagent.getKnowledgeBase();
+</programlisting>
+ </example>
+
+ <para>Resource scanning is not on by default, it's a service and must be
+ started, the same is for notification. This can be done via the
+ ResourceFactory.</para>
+
+ <example>
+ <title>Starting the Scanning and Notification Services</title>
+
+ <programlisting>ResourceFactory.getResourceChangeNotifierService().start();
+ResourceFactory.getResourceChangeScannerService().start();
+</programlisting>
+ </example>
+
+ <para>If you wish to change the default resource scanning period it must
+ be done on the ResourceChangeNotifierService. This can be done as the
+ configure(...) method which allows for the service to be reconfigured on
+ demand.</para>
+
+ <example>
+ <title>Changing the Scanning intervals</title>
+
+ <programlisting>ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
+sconf.setProperty( "drools.resource.scanner.interval",
+ "30" ); // set the disk scanning interval to 30s, default is 60s
+ResourceFactory.getResourceChangeScannerService().configure( sconf );
+</programlisting>
+ </example>
+
+ <para>KnowledgeAgents can take a empty KnowledgeBase or a populated one.
+ If a populated KnowledgeBase is provided, the KnowledgeAgent will iterate
+ KnowledgeBase and subscribe to the Resource that it finds. While it is
+ possible for the KnowledgeBuilder to build all resources found in a
+ directory, that information is lost by the KnowledgeBuilder so those
+ directories will not be continuously scanned. Only directories specified
+ as part of the applyChangeSet(Resource) method are monitored.</para>
+
+ <para>One of the advantages of providing KnowledgeBase as the starting
+ point is that you can provide it with a KnowledgeBaseConfiguration. When
+ resources changes are detected and a new KnowledgeBase is instantiated, it
+ will use the KnowledgeBaseConfiguration of the previous
+ KnowledgeBase.</para>
+
+ <example>
+ <title>Using an existing KnowledgeBase</title>
+
+ <programlisting>KnowledgeBaseConfiguration kbaseConf = KnowledgeBaseFactory.createKnowledgeBaseConfiguration( null, cl );
+KnowledgeBase kbase KnowledgeBaseFactory.newKnowledgeBase( kbaseConf );
+// populate kbase with resources here
+
+KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent",
+ kbase );
+KnowledgeBase kbase = kagent.getKnowledgeBase();
+</programlisting>
+ </example>
+
+ <para>In the above example the getKnowledgeBase will return the same
+ provided kbase instance until resource changes are detected and a new
+ KnowledgeBase is built. When the new KnowledgeBase is built, it will be
+ done with the KnowledgeBaseConfiguration that was provided to the previous
+ KnowledgeBase.</para>
+
+ <para>As mentioned previously a ChangeSet XML can specify a directory and
+ all it's contents will be added. If this ChangeSet XML is used with the
+ applyChangeSet method it will also add the directories to the scanning
+ process. When scanning directories added files will be detected and added
+ to the KnowledgeBase while remove files will be removed from the
+ KnowledgeBase and modified files will act as usual forcing a build of a
+ new KnowledgeBase using the latest version.</para>
+
+ <example>
+ <title>ChangeSet XML which adds a directories contents</title>
+
+ <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:/projects/myproject/myrules' type='PKG' />
+ </add>
+</change-set>
+</programlisting>
+ </example>
+
+ <para>Note if PKGs are the resource type the drools-compiler dependency is
+ not needed as the KnowledgeAgent is able to handle those with just
+ drools-core.</para>
+
+ <para>The KnowledgeAgentConfiguration can be used to change some default
+ behaviours, for instance you may want to load all the resources from a
+ directory, but not continously scan that directory for changes.</para>
+
+ <example>
+ <title>Changing the Scanning intervals</title>
+
+ <programlisting>KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+
+KnowledgeAgentConfiguration kaconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
+kaconf.setProperty( "drools.agent.scanDirectories",
+ "false" ); // we do not want to scan directories, just files
+
+KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
+ kaconf );
+</programlisting>
+ </example>
+
+ <para>Previously we mentioned Drools Guvnor and how it can build and
+ publish serialized KnowledgePackages on a URL. As shown previous the
+ ChangeSet XML can handle URLs and Packages, which forms an important
+ deployment scenario for the KnowledgeAgent.</para>
+ </section>
+</section>
Added: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Running.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Running.xml (rev 0)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-User_Guide/Section-Running.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -0,0 +1,1788 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<section 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>Running</title>
+
+ <para></para>
+
+ <section>
+ <title>KnowledgeBase</title>
+
+ <para>The KnowlegeBase is a repository of all the application's knowledge
+ definitions. It will contain rules, processes, functions, type models. The
+ KnowledgeBase itself does not contain data, instead sessions are created
+ from the KnowledgeBase in which data can be inserted and process instances
+ started. Creating the KnowlegeBase can be heavy, where as session creation
+ is very light, so it is recommended that KnowleBase's be cached where
+ possible to allow for repeated session creation.</para>
+
+ <example>
+ <title>Creating a new KnowledgeBuilder</title>
+
+ <programlisting>KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>StatefulKnowledgeSession</title>
+
+ <para>The StatefulKnowledgeSession stores and executes on the runtime data
+ and is created fom the KnowledgeBase.</para>
+
+ <figure>
+ <title>StatefulKnowledgeSession</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/StatefulKnowledgeSession.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <example>
+ <title>Add KnowledgePackages to a KnowledgeBase</title>
+
+ <programlisting>StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
+</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>KnowledgeRuntime</title>
+
+ <section>
+ <title>WorkingMemoryEntryPoint</title>
+
+ <para>The WorkingMemoryEntry provides the methods around inserting,
+ updating and retrieving facts. The term EntyPoint is related to the fact
+ that we have multiple partitions in a WorkingMemory and you can choose
+ which one you are inserting into, although this use case is aimed at
+ event processing and covered in more detail in the Fusion manual, most
+ rule based applications will work with the default entry point
+ alone.</para>
+
+ <para>The KnowledgeRuntime interface provides the main interaction with
+ the engine and is available in rule consequences and process actions. In
+ this manual the focus is on the methods and interfaces related to rules
+ and the process ones will be ignored for now. But you'll notice that hte
+ KnowledgeRuntime inherits methods from both the WorkingMemory and the
+ ProcessRuntime, this provides a unified api to work with process and
+ rules. When working with rules three interfaces form the
+ KnowledgeRuntime; WorkingMemoryEntryPoint, WorkingMemory and and the
+ KnowledgeRuntime itself.</para>
+
+ <figure>
+ <title>WorkingMemoryEntryPoint</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/WorkingMemoryEntryPoint.png"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <section>
+ <title>Insertion</title>
+
+ <para>"Insert" is the act of telling the <code>WorkingMemory</code>
+ about a fact, which you do by
+ <code>ksession.insert(yourObject)</code>, for example. When you insert
+ a fact, it is examined for matches against the rules. This means
+ <emphasis>all</emphasis> of the work for deciding about firing or not
+ firing a rule is done during insertion; no rule, however, is executed
+ until you call <code>fireAllRules()</code>, which you call
+ <code>fireAllRules()</code> after you have finished inserting your
+ facts. It is a common misunderstanding for people to think the
+ condition evaluation happens when you call
+ <code>fireAllRules()</code>. Expert systems typically use the term
+ <code>assert</code> or <code>assertion</code> to refer to facts made
+ available to the system. However due to the <code>assert</code> being
+ a keyword in most languages we have moved to use the
+ <code>insert</code> keyword; so expect to hear the two used
+ interchangeably.</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 inserted it returns a <code>FactHandle</code>.
+ This <code>FactHandle</code> is the token used to represent your
+ inserted object within the <code>WorkingMemory</code>. It is also used
+ for interactions with the <code>WorkingMemory</code> when you wish to
+ retract or modify an object.</para>
+
+ <programlisting>Cheese stilton = new Cheese("stilton");
+FactHandle stiltonHandle = ksession.insert( stilton ); </programlisting>
+
+ <para>As mentioned in the KnowledgeBase section a WorkingMemory may
+ operate in two assertion modes, i.e., equality or identity, with
+ identity being default.</para>
+
+ <para><emphasis>Identity</emphasis> means that the Working Memory uses
+ an <code>IdentityHashMap</code> to store all asserted objects. New
+ instance assertions always result in the return of a new
+ <code>FactHandle</code>, but if an instance is asserted again then it
+ returns the original fact handle, i.e., it ignores repeated insertions
+ for the same fact.</para>
+
+ <para><emphasis>Equality</emphasis> means that the Working Memory uses
+ a <code>HashMap</code> to store all asserted Objects. New instance
+ assertions will only return a new <code>FactHandle</code> if no equal
+ objects have been asserted.</para>
+ </section>
+
+ <section>
+ <title>Retraction</title>
+
+ <para>"Retraction" is the removal of a fact from the Working Memory,
+ which means it will no longer track and match that fact, and any rules
+ that are activated and dependent on that fact will be cancelled. Note
+ that it is possible to have rules that depend on the nonexistence of a
+ fact, in which case retracting a fact may cause a rule to activate
+ (see the <code>not</code> and <code>exist</code> keywords). Retraction
+ is done using the <code>FactHandle</code> that was returned during the
+ assert.</para>
+
+ <programlisting>Cheese stilton = new Cheese("stilton");
+FactHandle stiltonHandle = ksession.insert( stilton );
+....
+ksession.retract( stiltonHandle ); </programlisting>
+ </section>
+
+ <section>
+ <title>Update</title>
+
+ <para>The Rule Engine must be notified of modified Facts, so that they
+ can be reprocessed. Internally, modification is actually a retract and
+ then an insert; so it removes the fact from the
+ <code>WorkingMemory</code> and then inserts it again. You must use the
+ <code>update</code> method to notify the <code>WorkingMemory</code> of
+ changed objects for those objects that are not able to notify the
+ <code>WorkingMemory</code> themselves. Notice that <code>update</code>
+ always takes the modified object as a second parameter, which allows
+ you to specify new instances for immutable objects. The
+ <code>update</code> method can only be used with objects that have
+ shadow proxies turned on. The update keyworld is only used from java,
+ inside of a rule the "modify" keyword is supported and provides block
+ setters.</para>
+
+ <programlisting>Cheese stilton = new Cheese("stilton");
+FactHandle stiltonHandle = workingMemory.insert( stilton );
+....
+stilton.setPrice( 100 );
+workingMemory.update( stiltonHandle, stilton ); </programlisting>
+ </section>
+ </section>
+
+ <section>
+ <title>WorkingMemory</title>
+
+ <para>The WorkingMemory provides access to the Agenda, query executions
+ as well getting access to named EntyPoints,</para>
+
+ <figure>
+ <title>WorkingMemory</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/WorkingMemory.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <section>
+ <title>Query</title>
+
+ <para>Querries can be defined in the KnowlegeBase which can be called,
+ with optional parameters, to return the matching results. Any bound
+ identifier in the query can be accessed using the get(String
+ identifier) method.</para>
+
+ <figure>
+ <title>QueryResults</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/QueryResults.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <figure>
+ <title>QueryResultsRow</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/QueryResultsRow.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <example>
+ <title>Simple Query Example</title>
+
+ <programlisting>QueryResults results = ksession.getQueryResults( "my query", new Object[] { "string" } );
+for ( QueryResultsRow row : results ) {
+ System.out.println( row.get( "varName" ) );
+}</programlisting>
+ </example>
+ </section>
+ </section>
+
+ <section>
+ <title>KnowledgeRuntime</title>
+
+ <para>The KnowledgeRuntime provides further methods that are applicable
+ to both rules and processes. Such as setting globals and registering
+ ExitPoints.</para>
+
+ <figure>
+ <title>KnowledgeRuntime</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgeRuntime.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <section>
+ <title>Globals</title>
+
+ <para>Globals are named objects that can be passed in to the rule
+ engine, without needing to insert them. Most often these are used for
+ static information, or for services that are used in the RHS of a
+ rule, or perhaps as a means to return objects from the rule engine. If
+ you use a global on the LHS of a rule, make sure it is immutable. A
+ global must first be declared in a rules file before it can be set on
+ the session.</para>
+
+ <programlisting>global java.util.List list</programlisting>
+
+ <para>With the Knowledge Base now aware of the global identifier and
+ its type, it is now possible to call <code>ksession.setGlobal</code>
+ for any session. Failure to declare the global type and identifier
+ first will result in an exception being thrown. To set the global on
+ the session use <code>ksession.setGlobal(identifier,
+ value)</code>:</para>
+
+ <programlisting>List list = new ArrayList();
+ksession.setGlobal("list", list); </programlisting>
+
+ <para>If a rule evaluates on a global before you set it you will get a
+ <code>NullPointerException</code>.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>StatefulRuleSession</title>
+
+ <para>The StatefulRuleSession is inheritted by the
+ StatefulKnowledgeSession and provides the rule related methods that are
+ relevant from outside of the engine.</para>
+
+ <figure>
+ <title>StatefulRuleSession</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/StatefulRuleSession.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <section>
+ <title>Agenda Filters</title>
+
+ <figure>
+ <title>AgendaFilters</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-User_guide/AgendaFilter.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Agenda filters are optional implementations of the filter
+ interface which are used to allow or deny the firing of an activation.
+ What you filter on is entirely up to the implementation. Drools 4.0
+ used to supply some out of the box filters, which have not be exposed
+ in drools 5.0 drools-api, but they are simple to implement and the
+ Drools 4.0 code base can be referred to.</para>
+
+ <para>To use a filter specify it while calling
+ <code>FireAllRules</code>. The following example permits only rules
+ ending in the string <emphasis>Test</emphasis>. All others will be
+ filtered out. <programlisting>ksession.fireAllRules( new RuleNameEndsWithAgendaFilter( "Test" ) );</programlisting></para>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Agenda</title>
+
+ <para>The Agenda is a RETE feature. During actions on the
+ <code>WorkingMemory</code>, rules may become fully matched and eligible
+ for execution; a single Working Memory Action can result in multiple
+ eligible rules. When a rule is fully matched an Activation is created,
+ referencing the rule and the matched facts, and placed onto the Agenda.
+ The Agenda controls the execution order of these Activations using a
+ Conflict Resolution strategy.</para>
+
+ <para>The engine cycles repeatedly through two phases:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Working Memory Actions. This is where most of the work takes
+ place, either in the <code>Consequence</code> (the RHS itself) or the
+ main Java application process. Once the <code>Consequence</code> has
+ finished or the main Java application process calls
+ <code>fireAllRules()</code> the engine switches to the Agenda
+ Evaluation phase.</para>
+ </listitem>
+
+ <listitem>
+ <para>Agenda Evaluation. This attempts to select a rule to fire. If no
+ rule is found it exits, otherwise it fires the found rule, switching
+ the phase back to Working Memory Actions.</para>
+ </listitem>
+ </orderedlist>
+
+ <figure>
+ <title>Two Phase Execution</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
+ fileref="images/Chapter-Rule_Engine/Two_Phase.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The process repeats until the agenda is clear, in which case control
+ returns to the calling application. When Working Memory Actions are taking
+ place, no rules are being fired.</para>
+
+ <figure>
+ <title>Agenda</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/Agenda.png" format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <section>
+ <title>Conflict Resolution</title>
+
+ <para>Conflict resolution is required when there are multiple rules on
+ the agenda, the basics to this are covered in the "Quick Start" chapter.
+ As firing a rule may have side effects on working memory, the rule
+ engine needs to know in what order the rules should fire (for instance,
+ firing ruleA may cause ruleB to be removed from the agenda).</para>
+
+ <para>The default conflict resolution strategies employed by Drools are:
+ Salience and LIFO (last in, first out).</para>
+
+ <para>The most visible one is "salience" or priority, in which case a
+ user can specify that a certain rule has a higher priority (by giving it
+ a higher number) than other rules. In that case, the rule with higher
+ salience will be preferred. LIFO priorities are based on the assigned
+ Working Memory Action counter value, with all rules created during the
+ same action receiving the same value. The execution order of a set of
+ firings with the same priority value is arbitrary.</para>
+
+ <para>As a general rule, it is a good idea not to count on the rules
+ firing in any particular order, and to author the rules without worrying
+ about a "flow".</para>
+
+ <para>Drools 4.0 supported custom conflict resolution strategies, while
+ this capability still exists in Drools it has not yet been exposed to
+ the end user via drools-api in Drools 5.0.</para>
+ </section>
+
+ <section>
+ <title>AgendaGroup</title>
+
+ <figure>
+ <title>AgendaGroup</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/AgendaGroup.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Agenda groups are a way to partition rules (activations, actually)
+ on the agenda. At any one time, only one group has "focus" which means
+ that activations for rules in that group only will take effect. You can
+ also have rules with "auto focus" which means that the focus is taken
+ for its agenda group when that rule's conditions are true.</para>
+
+ <para>Agenda groups are known as "modules" in CLIPS terminology. They
+ provide a handy way to create a "flow" between grouped rules. You can
+ switch the group which has focus either from within the rule engine, or
+ via the API. If your rules have a clear need for multiple "phases" or
+ "sequences" of processing, consider using agenda-groups for this
+ purpose.</para>
+
+ <para>Each time <code>setFocus()</code> is called it pushes that Agenda
+ Group onto a stack. When the focus group is empty it is popped from the
+ stack and the focus group that is now on top evaluates. An Agenda Group
+ can appear in multiple locations on the stack. The default Agenda Group
+ is "MAIN", with all rules which do not specify an Agenda Group being in
+ this group. It is also always the first group on the stack, given focus
+ initially, by default.</para>
+
+ <para><programlisting>ksession.getAgenda().getAgendaGroup( "Group A" ).setFocus();</programlisting></para>
+ </section>
+
+ <section>
+ <title>ActivationGroup</title>
+
+ <figure>
+ <title>ActivationGroup</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/ActivationGroup.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>An activation group is group of rules associated together by the
+ "activation-group" rule attribute. In this group only one rule can fire,
+ after that rule has fired all the other rules are cancelled. The clear()
+ method can be called at any time, which cancels all of the activations
+ before one has a chance to fire. <programlisting>ksession.getAgenda().getActivationGroup( "Group B" ).clear();</programlisting></para>
+ </section>
+
+ <section>
+ <title>RuleFlowGroup</title>
+
+ <figure>
+ <title>RuleFlowGroup</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/RuleFlowGroup.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>A rule flow group is a group of rules associated by the
+ "ruleflow-group" rule attribute. These rules can only fire when the
+ group is activate. The group itself can only become active when the
+ ruleflow diagram representing it pr<programlisting>ksession.getAgenda().getRuleFlowGroup( "Group C" ).clear();</programlisting></para>
+ </section>
+ </section>
+
+ <section>
+ <title>Event Model</title>
+
+ <para>The event package provides means to be notified of rule engine
+ events, including rules firing, objects being asserted, etc. This allows
+ you, for instance, to separate logging and auditing activities from the
+ main part of your application (and the rules).</para>
+
+ <para>The KnowlegeRuntimeEventManager is implemented by the
+ KnowledgeRuntime which provides two interfaces, WorkingMemoryEventManager
+ and ProcessEventManager. We will only cover the WorkingMemoryEventManager
+ here.</para>
+
+ <figure>
+ <title>KnowledgeRuntimeEventManager</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgeRuntimeEventManager.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The WorkingMemoryEventManager allows for listeners to be added and
+ removed, so that events for the working memory and the agenda can be
+ listened to.</para>
+
+ <figure>
+ <title>WorkingMemoryEventManager</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/WorkingMemoryEventManager.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <example>
+ <title>Adding an AgendaEventListener</title>
+
+ <programlisting>ksession.addEventListener( new DefaultAgendaEventListener() {
+ public void afterActivationFired(AfterActivationFiredEvent event) {
+ super.afterActivationFired( event );
+ System.out.println( event );
+ }
+}); </programlisting>
+ </example>
+
+ <para>Drools also provides <code>DebugWorkingMemoryEventListener</code>,
+ <code>DebugAgendaEventListener</code> which implement each method with a
+ debug print statement. To print all Working Memory events, you add a
+ listener like this:</para>
+
+ <example>
+ <title>Creating a new KnowledgeBuilder</title>
+
+ <programlisting>ksession.addEventListener( new DebugWorkingMemoryEventListener() ); </programlisting>
+ </example>
+
+ <para>All emitted events implement the KnowlegeRuntimeEvent interface
+ which can be used to retrieve the actual KnowlegeRuntime the event
+ originated from.</para>
+
+ <figure>
+ <title>KnowlegeRuntimeEvent</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgeRuntimeEvent.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The events currently supported are:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>ActivationCreatedEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>ActivationCancelledEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>BeforeActivationFiredEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>AfterActivationFiredEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>AgendaGroupPushedEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>AgendaGroupPoppedEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>ObjectInsertEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>ObjectRetractedEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>ObjectUpdatedEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>ProcessCompletedEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>ProcessNodeLeftEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>ProcessNodeTriggeredEvent</para>
+ </listitem>
+
+ <listitem>
+ <para>ProcessStartEvent</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>KnowledgeRuntimeLogger</title>
+
+ <para>The KnowledgeRuntimeLogger uses the comprehensive event system in
+ Drools to create an audit log that can be used log the execution of drools
+ for later inspection, in tools such as the Eclipse audit viewer. </para>
+
+ <figure>
+ <title>KnowledgeRuntimeLoggerFactory</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/KnowledgeRuntimeLoggerFactory.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <example>
+ <title>FileLogger</title>
+
+ <programlisting>KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "logdir/mylogfile");
+....
+logger.close(); </programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>StatelessKnowledgeSession</title>
+
+ <para>The <code>StatelessKnowledgeSession</code> wraps the
+ <code>StatefulKnowledgeSession</code>, instead of extending it. Its main
+ focus is on decision service type scenarios. It removes the need to call
+ dispose(). Stateless sessions do not support iterative insertions and
+ fireAllRules from java code, the act of calling execute(...) is a single
+ shot method that will internally instantiate a StatefullKnowledgeSession,
+ add all the user data and execute user commands, call fireAllRules, and
+ then call dispose(). While the main way to work with this class is via the
+ BatchExecution Command as supported by the CommandExecutor interface, two
+ convenience methods are provided for when simple object insertion is all
+ that's required. The CommandExecutor and BatchExecution are talked about
+ in detail in their own section.</para>
+
+ <figure>
+ <title>StatelessKnowledgeSession</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/StatelessKnowledgeSession.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Simple example showing a stateless session executing for a given
+ collection of java objects using the convenience api. It will iterate the
+ collection inserting each element in turn</para>
+
+ <example>
+ <title>Simple StatelessKnowledgeSession execution with a
+ Collection</title>
+
+ <programlisting>KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+kbuilder.add( ResourceFactory.newFileSystemResource( fileName ), ResourceType.DRL );
+assertFalse( kbuilder.hasErrors() );
+if (kbuilder.hasErrors() ) {
+ System.out.println( kbuilder.getErrors() );
+}
+KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
+
+StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
+ksession.execute( collection ); </programlisting>
+ </example>
+
+ <para>If this was done as a single Command it would be as follows: </para>
+
+ <example>
+ <title>Simple StatelessKnowledgeSession execution with InsertElements
+ Command</title>
+
+ <programlisting>ksession.execute( CommandFactory.newInsertElements( collection ) ); </programlisting>
+ </example>
+
+ <para>Note if you wanted to insert the collection itself, and not the
+ iterate and insert the elements, then CommandFactory.newInsert( collection
+ ) would do the job.</para>
+
+ <para>The CommandFactory details the supported commands, all of which can
+ marshalled using XStream and the BatchExecutionHelper.
+ BatchExecutionHelper provides details on the xml format as well as how to
+ use Drools Pipeline to automate the marshalling of BatchExecution and
+ ExecutionResults.</para>
+
+ <para>StatelessKnowledgeSessions support globals, scoped in a number of
+ ways. I'll cover the non-command way first, as commands are scoped to a
+ specific execution call. Globals can be resolved in three ways. The
+ StatelessKnowledgeSession supports getGlobals(), which returns a Globals
+ instance. These globals are shared for ALL execution calls, so be
+ especially careful of mutable globals in these cases - as often execution
+ calls can be executing simultaneously in different threads. Globals also
+ supports a delegate, which adds a second way of resolving globals. Calling
+ of setGlobal(String, Object) will actually be set on an internal
+ Collection, identifiers in this internal Collection will have priority
+ over supplied delegate, if one is added. If an identifier cannot be found
+ in the internal Collection, it will then check the delegate Globals, if
+ one has been set.</para>
+
+ <example>
+ <title>Session scoped global</title>
+
+ <programlisting>StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
+ksession.setGlobal( "hbnSession", hibernateSession ); // sets a global hibernate session, that can be used for DB interactions in the rules.
+ksession.execute( collection ); // this will now execute and will be able to resolve the "hbnSession" identifier. </programlisting>
+ </example>
+
+ <para>The third way is execution scopped globals using the CommandExecutor
+ and SetGlobal Commands: </para>
+
+ <example>
+ <title>Execute scoped global</title>
+
+ <programlisting>StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
+ksession.setGlobal( "hbnSession", hibernateSession ); // sets a global hibernate session, that can be used for DB interactions in the rules.
+ksession.execute( collection ); // this will now execute and will be able to resolve the "hbnSession" identifier. </programlisting>
+ </example>
+
+ <para>The CommandExecutor interface also supports the ability to expert
+ data via "out" parameters. Inserted facts, globals and query results can
+ all be returned.</para>
+
+ <example>
+ <title>Out identifiers</title>
+
+ <programlisting> List cmds = new ArrayList();
+ cmds.add( CommandFactory.newSetGlobal( "list1", new ArrayList(), true ) );
+ cmds.add( CommandFactory.newInsert( new Person( "jon", 102 ), "person" ) );
+ cmds.add( CommandFactory.newQuery( "Get People" "getPeople" );
+
+ ExecutionResults results = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
+ results.getValue( "list1" ); // returns the ArrayList
+ results.getValue( "person" ); // returns the inserted fact Person
+ results.getValue( "Get People" );// returns the query as a QueryResults instance.
+ </programlisting>
+ </example>
+
+ <section>
+ <title><link linkend="sequential">Sequential Mode</link></title>
+
+ <para>With Rete you have a stateful session where objects can be
+ asserted and modified over time, and where rules can also be added and
+ removed. Now what happens if we assume a stateless session, where after
+ the initial data set no more data can be asserted or modified and rules
+ cannot be added or removed? Certainly it won't be necessary to
+ re-evaluate rules, and the engine will be able to operate in a
+ simplified way.</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Order the Rules by salience and position in the ruleset (by
+ setting a sequence attribute on the rule terminal node).</para>
+ </listitem>
+
+ <listitem>
+ <para>Create an array, one element for each possible rule
+ activation; element position indicates firing order.</para>
+ </listitem>
+
+ <listitem>
+ <para>Turn off all node memories, except the right-input Object
+ memory.</para>
+ </listitem>
+
+ <listitem>
+ <para>Disconnect the LeftInputAdapterNode propagation, and let the
+ Object plus the Node be referenced in a Command object, which is
+ added to a list on the WorkingMemory for later execution.</para>
+ </listitem>
+
+ <listitem>
+ <para>Assert all objects, and, when all assertions are finished and
+ thus right-input node memories are populated, check the Command list
+ and execute each in turn.</para>
+ </listitem>
+
+ <listitem>
+ <para>All resulting Activations should be placed in the array, based
+ upon the determined sequence number of the Rule. Record the first
+ and last populated elements, to reduce the iteration range.</para>
+ </listitem>
+
+ <listitem>
+ <para>Iterate the array of Activations, executing populated element
+ in turn.</para>
+ </listitem>
+
+ <listitem>
+ <para>If we have a maximum number of allowed rule executions, we can
+ exit our network evaluations early to fire all the rules in the
+ array.</para>
+ </listitem>
+ </orderedlist>
+
+ <para>The LeftInputAdapterNode no longer creates a Tuple, adding the
+ Object, and then propagate the Tuple – instead a Command Object is
+ created and added to a list in the Working Memory. This Command Object
+ holds a reference to the LeftInputAdapterNode and the propagated Object.
+ This stops any left-input propagations at insertion time, so that we
+ know that a right-input propagation will never need to attempt a join
+ with the left-inputs (removing the need for left-input memory). All
+ nodes have their memory turned off, including the left-input Tuple
+ memory but excluding the right-input Object memory, which means that the
+ only node remembering an insertion propagation is the right-input Object
+ memory. Once all the assertions are finished and all right-input
+ memories populated, we can then iterate the list of LeftInputAdatperNode
+ Command objects calling each in turn; they will propagate down the
+ network attempting to join with the right-input objects; not being
+ remembered in the left input, as we know there will be no further object
+ assertions and thus propagations into the right-input memory.</para>
+
+ <para>There is no longer an Agenda, with a priority queue to schedule
+ the Tuples, instead there is simply an array for the number of rules.
+ The sequence number of the RuleTerminalNode indicates the element with
+ the array to place the Activation. Once all Command Objects have
+ finished we can iterate our array checking each element in turn and
+ firing the Activations if they exist. To improve performance in the
+ array we remember the first and last populated cells. The network is
+ constructed where each RuleTerminalNode is given a sequence number,
+ based on a salience number and its order of being added to the
+ network.</para>
+
+ <para>Typically the right-input node memories are HashMaps, for fast
+ Object retraction; here, as we know there will be no Object retractions,
+ we can use a list when the values of the Object are not indexed. For
+ larger numbers of Objects indexed HashMaps provide a performance
+ increase; if we know an Object type has a low number of instances then
+ indexing is probably not of an advantage and an Object list can be
+ used.</para>
+
+ <para>Sequential mode can only be used with a StatelessSession and is
+ off by default. To turn on either set the
+ RuleBaseConfiguration.setSequential to true or set the rulebase.conf
+ property drools.sequential to true. Sequential mode can fall back to a
+ dynamic agenda with setSequentialAgenda to either
+ SequentialAgenda.SEQUENTIAL or SequentialAgenda.DYNAMIC set by a call or
+ via the "drools.sequential.agenda" property.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Pipeline</title>
+
+ <para>The PipelineFactory and associated classes are there to help with
+ the automation of getting information into and out of Drools, especially
+ when using services, such as JMS, and non pojo data sources. Transformers
+ for Smooks, JAXB, Xstream and Jxls are povided. Smooks is an ETL tooling
+ and can work with a variety of data sources, JAXB is a Java standard aimed
+ at working with XSDs, while XStream is a simple and fast xml serialisation
+ framework and finally Jxls allows for loading of pojos from an excel
+ decision table. minimal information on these technologies will be provided
+ here and it is expected for the user to consult the relevant user guide
+ for each.</para>
+
+ <figure>
+ <title>PipelineFactory</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/PipelineFactory.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Pipeline is not meant as a replacement for products like the more
+ powerful Camel, but is aimed as a complimentary framework that ultimately
+ can be integrated into more powerful pipeline frameworks. Instead it is a
+ simple framework aimed at the specific Drools use cases.</para>
+
+ <para>In Drools a pipeline is a series of stages that operate on and
+ propagate a given payload. Typically this starts with a Pipeline instance
+ which is responsible for taking the payload, creating a PipelineContext
+ for it and propagating that to the first Receiver stage. Two types of
+ Pipelines are provided, both requiring a different PipelineContexts.
+ StatefulKnowledgeSessionPipeline and StatelessKnowledgeSessionPipeline.
+ Notice that both factory methods take the relevant session as an
+ argument.</para>
+
+ <example>
+ <title>StatefulKnowledgeSessionPipeline</title>
+
+ <programlisting>Pipeline pipeline = PipelineFactory.newStatefulKnowledgeSessionPipeline( ksession );
+pipeline.setReceiver( receiver );</programlisting>
+ </example>
+
+ <para>A pipeline is then made up of a chain of Stages that can implement
+ both the Emitter and the Receiver interfaces. The Emitter interface means
+ the stage can propagate a payload and the Receiver interface means it can
+ receive a payload. This is why the Pipeline interface only implements
+ Emitter and Stage and not Receiver, as it is the first instance in the
+ chain. The Stage interface allows a custom exception handler to be set on
+ the stage.</para>
+
+ <example>
+ <title>StageExceptionHandler</title>
+
+ <programlisting>Transformer transformer = PipelineFactory.newXStreamFromXmlTransformer( xstream );
+transformer.setStageExceptionHandler( new StageExceptionHandler() { .... } );
+</programlisting>
+ </example>
+
+ <para>The Transformer interface above extends both Stage, Emitter and
+ Receiver, other than providing those interface methods as a single type,
+ it's other role is that of a marker interface that indicates the role of
+ the instance that implements it. We have several other marker interfaces
+ such as Expression and Action, both of which also extend Stage, Emitter
+ and Receiver. One of the stages should be responsible for setting a result
+ value on the PipelineContext. It is the role of the ResultHandler
+ interface, that the user implements that is responsible for executing on
+ these results or simply setting them an object that the user can retrieve
+ them from.</para>
+
+ <example>
+ <title>StageExceptionHandler</title>
+
+ <programlisting>ResultHandler resultHandler = new ResultHandlerImpl();
+pipeline.insert( factHandle, resultHandler );
+System.out.println( resultHandler );
+...
+public class ResultHandlerImpl implements ResultHandler {
+ Object result;
+
+ public void handleResult(Object result) {
+ this.result = result;
+ }
+
+ public Object getResult() {
+ return this.result;
+ }
+}
+</programlisting>
+ </example>
+
+ <para>While the above example shows a simple handler that simply assigns
+ the result to a field that the user can access, it could do more complex
+ work like sending the object as a message.</para>
+
+ <para>Pipeline is provides an adapter to insert the payload and internally
+ create the correct PipelineContext. Two types of Pipelines are provided,
+ both requiring a different PipelineContext.
+ StatefulKnowledgeSessionPipeline and StatelessKnowledgeSessionPipeline.
+ Pipeline itself implements both Stage and Emitter, this means it's a Stage
+ in a pipeline and emits the payload to a receiver. It does not implement
+ Receiver itself, as it the start adapter for the pipeline. PipelineFactory
+ provides methods to create both of the two Pipeline.
+ StatefulKnowledgeSessionPipeline is constructed as below, with the
+ receiver set.</para>
+
+ <para>In general it easier to construct the pipelines in reverse, for
+ example the following one handles loading xml data from disk, transforming
+ it with xstream and then inserting the object:</para>
+
+ <example>
+ <title>Constructing a pipeline</title>
+
+ <programlisting>// Make the results, in this case the FactHandles, available to the user
+Action executeResultHandler = PipelineFactory.newExecuteResultHandler();
+
+// Insert the transformed object into the session associated with the PipelineContext
+KnowledgeRuntimeCommand insertStage = PipelineFactory.newStatefulKnowledgeSessionInsert();
+insertStage.setReceiver( executeResultHandler );
+
+// Create the transformer instance and create the Transformer stage, where we are going from Xml to Pojo.
+XStream xstream = new XStream();
+Transformer transformer = PipelineFactory.newXStreamFromXmlTransformer( xstream );
+transformer.setReceiver( insertStage );
+
+// Create the start adapter Pipeline for StatefulKnowledgeSessions
+Pipeline pipeline = PipelineFactory.newStatefulKnowledgeSessionPipeline( ksession );
+pipeline.setReceiver( transformer );
+
+// Instantiate a simple result handler and load and insert the XML
+ResultHandlerImpl resultHandler = new ResultHandlerImpl();
+pipeline.insert( ResourceFactory.newClassPathResource( "path/facts.xml", getClass() ),
+ resultHandler );
+</programlisting>
+ </example>
+
+ <para>While the above example is for loading a resource from disk it is
+ also possible to work from a running messaging service. Drools currently
+ provides a single Service for JMS, called JmsMessenger. Support for other
+ Services will be added later. Below shows part of a unit test which
+ illustrates part of the JmsMessenger in action:</para>
+
+ <example>
+ <title>Using JMS with Pipeline</title>
+
+ <programlisting>// as this is a service, it's more likely the results will be logged or sent as a return message
+Action resultHandlerStage = PipelineFactory.newExecuteResultHandler();
+
+// Insert the transformed object into the session associated with the PipelineContext
+KnowledgeRuntimeCommand insertStage = PipelineFactory.newStatefulKnowledgeSessionInsert();
+insertStage.setReceiver( resultHandlerStage );
+
+// Create the transformer instance and create the Transformer stage, where we are going from Xml to Pojo. Jaxb needs an array of the available classes
+JAXBContext jaxbCtx = KnowledgeBuilderHelper.newJAXBContext( classNames,
+ kbase );
+Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller();
+Transformer transformer = PipelineFactory.newJaxbFromXmlTransformer( unmarshaller );
+transformer.setReceiver( insertStage );
+
+// payloads for JMS arrive in a Message wrapper, we need to unwrap this object
+Action unwrapObjectStage = PipelineFactory.newJmsUnwrapMessageObject();
+unwrapObjectStage.setReceiver( transformer );
+
+// Create the start adapter Pipeline for StatefulKnowledgeSessions
+Pipeline pipeline = PipelineFactory.newStatefulKnowledgeSessionPipeline( ksession );
+pipeline.setReceiver( unwrapObjectStage );
+
+// Services, like JmsMessenger take a ResultHandlerFactory implementation, this is because a result handler must be created for each incoming message.
+ResultHandleFactoryImpl factory = new ResultHandleFactoryImpl();
+Service messenger = PipelineFactory.newJmsMessenger( pipeline,
+ props,
+ destinationName,
+ factory );
+messenger.start();
+</programlisting>
+ </example>
+
+ <section>
+ <title>Xstream Transformer</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>JAXB Transformer</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Smooks Transformer</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Smooks Transformer</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>JMS Messenger</title>
+
+ <para></para>
+ </section>
+ </section>
+
+ <section>
+ <title>Commands and the CommandExecutor</title>
+
+ <para>Drools has the concept of stateful or stateless sessions, we've
+ already covered stateful. Where stateful is the standard working memory
+ that can be worked with iteratively over time. Stateless is a one off
+ execution of a working memory with a provided data set and optionally
+ returning some results with the session disposed at the end, prohibiting
+ further iterative interactions. You can think of stateless as treating a
+ rule engine like a function call with optional return results.</para>
+
+ <para>In Drools 4 we supported these two paradigms but the way the user
+ interacted with them was different. StatelessSession used an execute(...)
+ method which would insert a collection of objects as facts.
+ StatefulSession didn't have this method and insert used the more
+ traditional insert(...) method. The other issue was the StatelessSession
+ did not return any results, the user was expected to map globals
+ themselves to get results, and it wasn't possible to do anything else
+ other than insert objects, users could not start processes or execute
+ querries.</para>
+
+ <para>Drools 5.0 addresses all of these issues and more. The foundations
+ for this is the CommandExecutor interface, which both the stateful and
+ stateless interfaces extend creating consistency and
+ ExecutionResults:</para>
+
+ <figure>
+ <title>CommandExecutor</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/CommandExecutor.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <figure>
+ <title>ExecutionResults</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/ExecutionResults.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The CommandFactory allows for commands to be executed on those
+ sessions, only only difference being the StatelessKnowledgeSession
+ executes fireAllRules() at the end before disposing the session. The
+ current supported commands are:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>FireAllRules</para>
+ </listitem>
+
+ <listitem>
+ <para>GetGlobal</para>
+ </listitem>
+
+ <listitem>
+ <para>SetGlobal</para>
+ </listitem>
+
+ <listitem>
+ <para>InsertObject</para>
+ </listitem>
+
+ <listitem>
+ <para>InsertElements</para>
+ </listitem>
+
+ <listitem>
+ <para>Query</para>
+ </listitem>
+
+ <listitem>
+ <para>StartProcess</para>
+ </listitem>
+
+ <listitem>
+ <para>BatchExecution</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>InsertObject will insert a single object, with an optional out
+ identifier. InsertElements will iterate an Iterable inserting each of the
+ elements. What this means is that StatelessKnowledgeSession are no longer
+ limited to just inserting objects, they can now start processes or execute
+ querries and in any order.</para>
+
+ <example>
+ <title>Insert Command</title>
+
+ <programlisting>StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
+ExecutionResults bresults = ksession.execute( CommandFactory.newInsert( new Cheese( "stilton" ), "stilton_id" ) );
+Stilton stilton = bresults.getValue( "stilton_id" );
+</programlisting>
+ </example>
+
+ <para>The execute method always returns an ExecutionResults instance,
+ which allows access to any command results if they specify an out
+ identifier such as the "stilton_id" above.</para>
+
+ <example>
+ <title>InsertElements Command</title>
+
+ <programlisting>StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
+Command cmd = CommandFactory.newInsertElements( Arrays.asList( Object[] {
+ new Cheese( "stilton" ),
+ new Cheese( "brie" ),
+ new Cheese( "cheddar" ),
+ });
+ExecutionResults bresults = ksession.execute( cmd );
+</programlisting>
+ </example>
+
+ <para>What you say, the method only allows for a single command? That's
+ Where the BatchExecution comes in, this is a composite command that takes
+ a list of commands and will iterate and execute each command in turn. This
+ means you can insert some objects, start a process, call fireAllRules and
+ execute a query all in a single execute(...) call - much more
+ powerful.</para>
+
+ <para>As mentioned the StatelessKnowledgeSession by default will execute
+ fireAllRules() automatically at the end. However the keen eyed reader
+ probably has already noticed the FireAllRules command and wondering how
+ that works with a StatelessKnowledgeSession. The FireAllRules command is
+ allowed and using it will disable the automatic execution at the end,
+ think of using it as a sort of manual override.</para>
+
+ <para>So this is great, we've brought consistency to how
+ StatelessKnowledgeSession and StatefullKnowledgeSession work and also
+ brought in support for more than just inserting objects. What about result
+ handling? Rather than using parameters, like my first attempt which always
+ bugged me, these commands support out identifiers. Any command that has an
+ out identifier set on it will add it's results to the returned
+ ExecutionResults instance. Let's look at a simple example to see how this
+ works.</para>
+
+ <example>
+ <title>BatchExecution Command</title>
+
+ <programlisting>StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
+
+List cmds = new ArrayList();
+cmds.add( CommandFactory.newInsertObject( new Cheese( "stilton", 1), "stilton") );
+cmds.add( CommandFactory.newStartProcess( "process cheeses" ) );
+cmds.add( CommandFactory.newQuery( "cheeses" ) );
+ExecutionResults bresults = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
+QueryResults qresults = ( QueryResults ) bresults.getValue( "cheeses" );
+Cheese stilton = ( Cheese ) bresults.getValue( "silton" );
+</programlisting>
+ </example>
+
+ <para>So in the above example you saw how multiple commands where executed
+ two of which populate the ExecutionResults. The query command defaults to
+ use the same identifier as the query name, but it can also be mapped to a
+ different identifier.</para>
+
+ <para>So now we have consistency across stateless and stateful sessions,
+ ability to execute a variety of commands and an elegant way to deal with
+ results. Does it get better than this? Absolutely we've built a custom
+ XStream marshaller that can be used with the Drools Pipeline to get XML
+ scripting, which is perfect for services. Here are two simple xml samples
+ for the BatchExecution and ExecutionResults.</para>
+
+ <example>
+ <title>Simple BatchExecution XML</title>
+
+ <programlisting><batch-execution>
+ <insert out-identifier='outStilton'>
+ <org.drools.Cheese>
+ <type>stilton</type>
+ <price>25</price>
+ <oldPrice>0</oldPrice>
+ </org.drools.Cheese>
+ </insert>
+</batch-execution>
+</programlisting>
+ </example>
+
+ <example>
+ <title>Simple ExecutionResults XML</title>
+
+ <programlisting><execution-results>
+ <result identifier='outStilton'>
+ <org.drools.Cheese>
+ <type>stilton</type>
+ <oldPrice>0</oldPrice>
+ <price>30</price>
+ </org.drools.Cheese>
+ </result>
+</execution-results>
+</programlisting>
+ </example>
+
+ <para>I've mentioned the pipeline previously, it allows for a series of
+ stages to be used together to help with getting data into and out of
+ sessions. There is a stage that supports the CommandExecutor interface and
+ allows the pipeline to script either a stateful or stateless session. The
+ pipeline setup is trivial:</para>
+
+ <example>
+ <title>Pipeline use for CommandExecutor</title>
+
+ <programlisting>Action executeResultHandler = PipelineFactory.newExecuteResultHandler();
+
+Action assignResult = PipelineFactory.newAssignObjectAsResult();
+assignResult.setReceiver( executeResultHandler );
+
+Transformer outTransformer = PipelineFactory.newXStreamToXmlTransformer( BatchExecutionHelper.newXStreamMarshaller() );
+outTransformer.setReceiver( assignResult );
+
+KnowledgeRuntimeCommand cmdExecution = PipelineFactory.newCommandExecutor();
+batchExecution.setReceiver( cmdExecution );
+
+Transformer inTransformer = PipelineFactory.newXStreamFromXmlTransformer( BatchExecutionHelper.newXStreamMarshaller() );
+inTransformer.setReceiver( batchExecution );
+
+Pipeline pipeline = PipelineFactory.newStatelessKnowledgeSessionPipeline( ksession );
+pipeline.setReceiver( inTransformer );
+</programlisting>
+ </example>
+
+ <para>The key thing here to note is the use of the BatchExecutionHelper to
+ provide a specially configured XStream with custom converters for our
+ Commands and the new BatchExecutor stage.</para>
+
+ <para>Using the pipeline is very simple, you must provide your own
+ implementation of the ResultHandler, which is called if the pipeline
+ executes the ExecuteResultHandler stage.</para>
+
+ <figure>
+ <title>Pipeline ResultHandler</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/ResultHandler.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <example>
+ <title>Simple Pipeline ResultHandler</title>
+
+ <programlisting>public static class ResultHandlerImpl implements ResultHandler {
+ Object object;
+
+ public void handleResult(Object object) {
+ this.object = object;
+ }
+
+ public Object getObject() {
+ return this.object;
+ }
+}
+</programlisting>
+ </example>
+
+ <example>
+ <title>Using a Pipeline</title>
+
+ <programlisting>ResultHandler resultHandler = new ResultHandlerImpl();
+pipeline.insert( inXml, resultHandler );
+</programlisting>
+ </example>
+
+ <para>Earlier a BatchExecution was created with java to insert some
+ objects and execute a query. The XML representation to be used with the
+ pipeline for that example is shown below, for added fun I've added
+ parameters to the query.</para>
+
+ <example>
+ <title>BatchExecution Marshalled to XML</title>
+
+ <programlisting><batch-execution>
+ <insert out-identifier="stilton">
+ <org.drools.Cheese>
+ <type>stilton</type>
+ <price>1</price>
+ </org.drools.Cheese>
+ </insert>
+ <query out-identifier='cheeses2' name='cheesesWithParams'>
+ <string>stilton</string>
+ <string>cheddar</string>
+ </query>
+</batch-execution>
+</programlisting>
+ </example>
+
+ <para>The CommandExecutor returns an ExecutionResults, this too is handled
+ by the pipeline code snippet. A similar output for the
+ <batch-execution> xml sample above would be:</para>
+
+ <example>
+ <title>ExecutionResults Marshalled to XML</title>
+
+ <programlisting><execution-results>
+ <result identifier="stilton">
+ <org.drools.Cheese>
+ <type>stilton</type>
+ <price>2</price>
+ </org.drools.Cheese>
+ </result>
+ <result identifier='cheeses2'>
+ <query-results>
+ <identifiers>
+ <identifier>cheese</identifier>
+ </identifiers>
+ <row>
+ <org.drools.Cheese>
+ <type>cheddar</type>
+ <price>2</price>
+ <oldPrice>0</oldPrice>
+ </org.drools.Cheese>
+ </row>
+ <row>
+ <org.drools.Cheese>
+ <type>cheddar</type>
+ <price>1</price>
+ <oldPrice>0</oldPrice>
+ </org.drools.Cheese>
+ </row>
+ </query-results>
+ </result>
+</execution-results>
+</programlisting>
+ </example>
+
+ <para>The BatchExecutionHelper provides a configured XStream instance to
+ support the marshalling of BatchExecutions, where the resulting xml can be
+ used as a message format, as shown above. Configured converters only exist
+ for the commands supported via the CommandFactory. The user may add other
+ converters for their user objects. This is very useful for scripting
+ stateless of stateful knowledge sessions, especially when services are
+ involed.</para>
+
+ <para>There is current no xsd for schema validation, however we will try
+ to outline the basic format here and the drools-transformer-xstream module
+ has an illustrative unit test in the XStreamBatchExecutionTest unit test.
+ The root element is <batch-execution> and it can contain zero or
+ more commands elements.</para>
+
+ <example>
+ <title>Root XML element</title>
+
+ <programlisting><batch-execution>
+...
+</batch-execution>
+</programlisting>
+ </example>
+
+ <para>This contains a list of elements that represent commands, the
+ supported commands is limited to those Commands provided by the
+ CommandFactory. The most basic of these is the <insert> element,
+ which inserts objects. The contents of the insert element is the user
+ object, as dictated by XStream.</para>
+
+ <example>
+ <title>Insert with Out Identifier Command</title>
+
+ <programlisting><batch-execution>
+ <insert>
+ ....
+ </insert>
+</batch-execution>
+</programlisting>
+ </example>
+
+ <para>The insert element supports an 'out-identifier' attribute, this
+ means the insert object will also be returned as part of the
+ payload.</para>
+
+ <example>
+ <title>Insert with Out Identifier Command</title>
+
+ <programlisting><batch-execution>
+ <insert out-identifier='userVar'>
+ ....
+ </insert>
+</batch-execution>
+</programlisting>
+ </example>
+
+ <para>It's also possible to insert a collection of objects using the
+ <insert-elements> element, however this command does not support an
+ out-identifier. The org.domain.UserClass is just an illustrative user
+ object that xstream would serialise.</para>
+
+ <example>
+ <title>Insert Elements command</title>
+
+ <programlisting><batch-execution>
+ <insert-elements>
+ <org.domain.UserClass>
+ ...
+ </org.domain.UserClass>
+ <org.domain.UserClass>
+ ...
+ </org.domain.UserClass>
+ <org.domain.UserClass>
+ ...
+ </org.domain.UserClass>
+ </insert-elements>
+</batch-execution>
+</programlisting>
+ </example>
+
+ <para>Next there is the <set-global> element, which sets a global
+ for the session.</para>
+
+ <example>
+ <title>Insert Elements command</title>
+
+ <programlisting><batch-execution>
+ <set-global identifier='userVar'>
+ <org.domain.UserClass>
+ ...
+ </org.domain.UserClass>
+ </set-global>
+</batch-execution>
+</programlisting>
+ </example>
+
+ <para><set-global> also supports two other optional attributes 'out'
+ and 'out-identifier'. 'out' is a boolean and when set the global will be
+ added to the <batch-execution-results&g; payload using the name
+ from the 'identifier' attribute. 'out-identifier' works like 'out' but
+ additionally allows you to override the identifier used in the
+ <batch-execution-results&g; payload.</para>
+
+ <example>
+ <title>Set Global Command</title>
+
+ <programlisting><batch-execution>
+ <set-global identifier='userVar1' out='true'>
+ <org.domain.UserClass>
+ ...
+ </org.domain.UserClass>
+ </set-global>
+ <set-global identifier='userVar2' out-identifier='alternativeUserVar2'>
+ <org.domain.UserClass>
+ ...
+ </org.domain.UserClass>
+ </set-global>
+</batch-execution>
+</programlisting>
+ </example>
+
+ <para>There is also a <get-global> element, which has no contents
+ but does support an 'out-identifier' attribute, there is no need for an
+ 'out' attribute as we assume that a <get-global> is always an
+ 'out'.</para>
+
+ <example>
+ <title>Get Global Command</title>
+
+ <programlisting><batch-execution>
+ <get-global identifier='userVar1' />
+ <get-global identifier='userVar2' out-identifier='alternativeUserVar2'/>
+</batch-execution>
+</programlisting>
+ </example>
+
+ <para>While the 'out' attribute is useful in returning specific instances
+ as a result payload, we often wish to run actual querries. Both parameter
+ and parameterless querries are supported. The 'name' attribute is the name
+ of the query to be called, and the 'out-identifier' is the identifier to
+ be used for the query results in the <execution-results>
+ payload.</para>
+
+ <example>
+ <title>Query Command</title>
+
+ <programlisting><batch-execution>
+ <query out-identifier='cheeses' name='cheeses'/>
+ <query out-identifier='cheeses2' name='cheesesWithParams'>
+ <string>stilton</string>
+ <string>cheddar</string>
+ </query>
+</batch-execution>
+</programlisting>
+ </example>
+
+ <para>Drools is no longer just about rules, os the <start-process>
+ command is also supported and accepts optional parameters. Other process
+ related methods will be added later, like interacting with work
+ items.</para>
+
+ <example>
+ <title>Start Process Command</title>
+
+ <programlisting><batch-execution>
+ <startProcess processId='org.drools.actions'>
+ <parameter identifier='person'>
+ <org.drools.TestVariable>
+ <name>John Doe</name>
+ </org.drools.TestVariable>
+ </parameter>
+ </startProcess>
+</batch-execution
+</programlisting>
+ </example>
+
+ <para>Support for more commands will be added over time.</para>
+ </section>
+
+ <section>
+ <title>Marshalling</title>
+
+ <para>The MarshallerFactory is used to marshal and unmarshal
+ StatefulKnowledgeSessions.</para>
+
+ <figure>
+ <title>MarshallerFactory</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/Chapter-User_Guide/MarshallerFactory.png"
+ format=""></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>At the simplest the MarshallerFactory can be used as follows:</para>
+
+ <example>
+ <title>Simple Marshaller Example</title>
+
+ <programlisting>// ksession is the StatefulKnowledgeSession
+// kbase is the KnowledgeBase
+ByteArrayOutputStream baos = new ByteArrayOutputStream();
+Marshaller marshaller = MarshallerFactory.newMarshaller( kbase );
+marshaller.marshall( baos, ksession );
+baos.close();
+</programlisting>
+ </example>
+
+ <para>However with marshalling you need more flexibility when dealing with
+ referenced user data. To achieve this we have the
+ ObjectMarshallingStrategy interface. Two implementations are provided, but
+ the user can implement their own. The two supplied are
+ IdentityMarshallingStrategy and SerializeMarshallingStrategy.
+ SerializeMarshallingStrategy is the default, as used in the example above
+ and it just calls the Serializable or Externalizable methods on a user
+ instance. IdentityMarshallingStrategy instead creates an int id for each
+ user object and stores them in a Map the id is written to the stream. When
+ unmarshalling it simply looks to the IdentityMarshallingStrategy map to
+ retrieve the instance. This means that if you use the
+ IdentityMarshallingStrategy it's stateful for the life of the Marshaller
+ instance and will create ids and keep references to all objects that it
+ attempts to marshal. Here is he code to use a
+ IdentityMarshallingStrategy.</para>
+
+ <example>
+ <title>IdentityMarshallingStrategy</title>
+
+ <programlisting>ByteArrayOutputStream baos = new ByteArrayOutputStream();
+Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[] { MarshallerFactory.newIdentityMarshallingStrategy() } );
+marshaller.marshall( baos, ksession );
+baos.close();
+</programlisting>
+ </example>
+
+ <para>For added flexability we can't assume that a single strategy is
+ suitable for this we have added the ObjectMarshallingStrategyAcceptor
+ interface that each ObjectMarshallingStrategy has. The Marshaller has a
+ chain of strategies and when it attempts to read or write a user object it
+ iterates the strategies asking if they accept responsability for
+ marshalling the user object. One one implementation is provided the
+ ClassFilterAcceptor. This allows strings and wild cards to be used to
+ match class names. The default is "*.*", so in the above the
+ IdentityMarshallingStrategy is used which has a default "*.*"
+ acceptor.</para>
+
+ <para>But lets say we want to serialise all classes except for one given
+ package, where we will use identity lookup, we could do the
+ following:</para>
+
+ <example>
+ <title>IdentityMarshallingStrategy with Acceptor</title>
+
+ <programlisting>ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ObjectMarshallingStrategyAcceptor identityAceceptor = MarshallerFactory.newClassFilterAcceptor( new String[] { "org.domain.pkg1.*" } );
+ObjectMarshallingStrategy identityStratetgy = MarshallerFactory.newIdentityMarshallingStrategy( identityAceceptor );
+Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[] { identityStratetgy, MarshallerFactory.newSerializeMarshallingStrategy() } );
+marshaller.marshall( baos, ksession );
+baos.close();
+</programlisting>
+ </example>
+
+ <para>Note that the acceptance checking order is in the natural order of
+ the supplied array.</para>
+ </section>
+
+ <section>
+ <title>Persistence and Transactions</title>
+
+ <para>Long term out of the box persistence with JPA is possible with
+ Drools. You will need to have JTA installed, for development purposes we
+ recommend Bitronix as it's simple to setup and works embedded, but for
+ production use JBoss Transactions is recommended.</para>
+
+ <example>
+ <title>Simple exapmle using transactions</title>
+
+ <programlisting>Environment env = KnowledgeBaseFactory.newEnvironment();
+env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, Persistence.createEntityManagerFactory( "emf-name" ) );
+env.set( EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager() );
+
+StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env ); // KnowledgeSessionConfiguration may be null, and a default will be used
+int sessionId = ksession.getId();
+
+UserTransaction ut = (UserTransaction) new InitialContext().lookup( "java:comp/UserTransaction" );
+ut.begin();
+ksession.insert( data1 );
+ksession.insert( data2 );
+ksession.startProcess( "process1" );
+ut.commit();
+</programlisting>
+ </example>
+
+ <para>To use a JPA the Environment must be set with both the
+ EntityManagerFactory and the TransactionManager. If rollback occurs the
+ ksession state is also rolled back, so you can continue to use it after a
+ rollback. To load a previous persisted StatefulKnowledgeSession you'll
+ need the id, as shown below:</para>
+
+ <example>
+ <title>Loading a StatefulKnowledgeSession</title>
+
+ <programlisting>StatefulKnowledgeSession ksession = JPAKnowledgeService.loadStatefulKnowledgeSession( sessionId, kbase, null, env );
+</programlisting>
+ </example>
+
+ <para>To enable persistence the following classes must be added to your
+ persistence.xml, as in the example below:</para>
+
+ <example>
+ <title>Configuring JPA</title>
+
+ <programlisting><persistence-unit name="org.drools.persistence.jpa" transaction-type="JTA">
+ <provider>org.hibernate.ejb.HibernatePersistence</provider>
+ <jta-data-source>jdbc/BitronixJTADataSource</jta-data-source>
+ <class>org.drools.persistence.session.SessionInfo</class>
+ <class>org.drools.persistence.processinstance.ProcessInstanceInfo</class>
+ <class>org.drools.persistence.processinstance.ProcessInstanceEventInfo</class>
+ <class>org.drools.persistence.processinstance.WorkItemInfo</class>
+ <properties>
+ <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
+ <property name="hibernate.max_fetch_depth" value="3"/>
+ <property name="hibernate.hbm2ddl.auto" value="update" />
+ <property name="hibernate.show_sql" value="true" />
+ <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup" />
+ </properties>
+</persistence-unit>
+</programlisting>
+ </example>
+
+ <para>The jdbc JTA data source would need to be previously bound, Bitronix
+ provides a number of ways of doing this and it's docs shoud be contacted
+ for more details, however for quick start help here is the programmatic
+ approach:</para>
+
+ <example>
+ <title>Configuring JTA DataSource</title>
+
+ <programlisting>PoolingDataSource ds = new PoolingDataSource();
+ds.setUniqueName( "jdbc/BitronixJTADataSource" );
+ds.setClassName( "org.h2.jdbcx.JdbcDataSource" );
+ds.setMaxPoolSize( 3 );
+ds.setAllowLocalTransactions( true );
+ds.getDriverProperties().put( "user", "sa" );
+ds.getDriverProperties().put( "password", "sasa" );
+ds.getDriverProperties().put( "URL", "jdbc:h2:mem:mydb" );
+ds.init();
+</programlisting>
+ </example>
+
+ <para>Bitronix also provides a simple embedded JNDI service, ideal for
+ testing, to use it add a jndi.properties file to your META-INF and add the
+ following line to it:</para>
+
+ <example>
+ <title>JNDI properties</title>
+
+ <programlisting>java.naming.factory.initial=bitronix.tm.jndi.BitronixInitialContextFactory
+</programlisting>
+ </example>
+ </section>
+</section>
Modified: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/master.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/master.xml 2009-04-16 11:50:03 UTC (rev 26060)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/master.xml 2009-04-16 11:52:31 UTC (rev 26061)
@@ -8,53 +8,13 @@
<title>Drools Expert User Guide</title>
<releaseinfo>5.0.0.SNAPSHOT</releaseinfo>
-
- <author>
- <personname>
- <firstname>Mark</firstname>
- <surname>Proctor</surname>
- </personname>
- </author>
-
- <author>
- <personname>
- <firstname>Michael</firstname>
- <surname>Neale</surname>
- </personname>
- </author>
-
- <author>
- <personname>
- <firstname>Edson</firstname>
- <surname>Tirelli</surname>
- </personname>
- </author>
</info>
-
- <!--
- <preface id="preface" revision="2"> <title>Preface</title>
-
- <mediaobject> <imageobject> <imagedata fileref="drools_logo.png" />
- </imageobject> </mediaobject> <para /> </preface>
- -->
-
- <xi:include href="Acknowledgements.xml" />
-
+ <xi:include href="Chapter-Introduction/Chapter-Introduction.xml" />
<xi:include href="Chapter-Quick_Start/Chapter-Quick_Start.xml" />
-
- <xi:include href="Chapter-Rule_Engine/Chapter-Rule_Engine.xml" />
-
- <xi:include href="Chapter-Decision_Tables/Chapter-Spreadsheet.xml" />
-
- <xi:include href="Chapter-IDE/Chapter-QuickStart.xml" />
-
- <xi:include href="Chapter-Deployment/Chapter-DepymentAndTest.xml" />
-
- <xi:include href="Chapter-JSR94/Chapter-JSR94.xml" />
-
- <xi:include href="Chapter-Rule_Language/Chapter-RuleLanguage.xml" />
-
- <xi:include href="Chapter-Examples/Chapter-Examples.xml" />
-
- <index />
+ <xi:include href="Chapter-User_Guide/Chapter-User_Guide.xml" />
+ <xi:include href="Chapter-Language_Reference/Chapter-Language_Reference.xml" />
+ <xi:include href="Chapter-Authoring/Chapter-Authoring.xml" />
+ <xi:include href="Chapter-JSR94/Chapter-JSR94.xml" />
+ <xi:include href="Chapter-Examples/Chapter-Examples.xml" />
+ <!--index /-->
</book>
More information about the jboss-svn-commits
mailing list