[jboss-svn-commits] JBL Code SVN: r25429 - in labs/jbossrules/trunk: drools-guvnor/src/main/java/org/drools/guvnor/server/files and 3 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Feb 26 01:49:19 EST 2009


Author: michael.neale at jboss.com
Date: 2009-02-26 01:49:19 -0500 (Thu, 26 Feb 2009)
New Revision: 25429

Modified:
   labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Decision_Tables/Chapter-Spreadsheet.xml
   labs/jbossrules/trunk/drools-guvnor/src/main/java/org/drools/guvnor/server/files/FileManagerUtils.java
   labs/jbossrules/trunk/drools-guvnor/src/main/java/org/drools/guvnor/server/files/RepositoryBackupServlet.java
   labs/jbossrules/trunk/drools-guvnor/src/test/java/org/drools/guvnor/server/util/FileManagerUtilsTest.java
   labs/jbossrules/trunk/drools-repository/src/main/java/org/drools/repository/RulesRepository.java
   labs/jbossrules/trunk/drools-repository/src/test/java/org/drools/repository/RulesRepositoryTest.java
Log:
GUVNOR-153 and more fixes for exporting

Modified: labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Decision_Tables/Chapter-Spreadsheet.xml
===================================================================
--- labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Decision_Tables/Chapter-Spreadsheet.xml	2009-02-26 04:53:09 UTC (rev 25428)
+++ labs/jbossrules/trunk/drools-docs/drools-docs-expert/src/main/docbook/en-US/Chapter-Decision_Tables/Chapter-Spreadsheet.xml	2009-02-26 06:49:19 UTC (rev 25429)
@@ -1,711 +1,800 @@
-<?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>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" />
-				</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 &lt; $1, baz == $2)] and the cell is [42,42] then the result will be [Foo(bar &gt; 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" />
-            </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" />
-            </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" />
-            </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" />
-            </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" />
-            </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>
-  
-</chapter>
+<?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:m="http://www.w3.org/1998/Math/MathML"
+         xmlns:html="http://www.w3.org/1999/xhtml"
+         xmlns:db="http://docbook.org/ns/docbook">
+  <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" />
+        </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
+        &lt; $1, baz == $2)] and the cell is [42,42] then the result will be
+        [Foo(bar &gt; 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>
+//first we compile the spreadsheet with the template
+//to create a whole lot of rules.
+final ExternalSpreadsheetCompiler converter = new ExternalSpreadsheetCompiler();
+//the data we are interested in starts at row 2, column 2 (e.g. B2)
+final String drl = converter.compile(getSpreadsheetStream(), getRulesStream(), 2, 2);
+</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>
+</chapter>

Modified: labs/jbossrules/trunk/drools-guvnor/src/main/java/org/drools/guvnor/server/files/FileManagerUtils.java
===================================================================
--- labs/jbossrules/trunk/drools-guvnor/src/main/java/org/drools/guvnor/server/files/FileManagerUtils.java	2009-02-26 04:53:09 UTC (rev 25428)
+++ labs/jbossrules/trunk/drools-guvnor/src/main/java/org/drools/guvnor/server/files/FileManagerUtils.java	2009-02-26 06:49:19 UTC (rev 25429)
@@ -222,15 +222,6 @@
 
     }
 
-    public byte[] exportRulesRepository() {
-        try {
-            return this.repository.exportRulesRepository();
-        } catch ( RepositoryException e ) {
-            throw new RulesRepositoryException( e );
-        } catch ( IOException e ) {
-            throw new RulesRepositoryException( e );
-        }
-    }
 
     public byte[] exportPackageFromRepository(String packageName) {
         try {
@@ -242,14 +233,18 @@
         }
     }
 
+    public void exportRulesRepository(OutputStream out) {
+        this.repository.exportRulesRepositoryToStream(out);
+    }
+
     @Restrict("#{identity.loggedIn}")
-    public void importRulesRepository(byte[] data) {
+    public void importRulesRepository(InputStream in) {
 		if (Contexts.isSessionContextActive()) {
 			Identity.instance().checkPermission(
 					new AdminType(),
 					RoleTypes.ADMIN);
 		}
-        repository.importRulesRepository( data );
+        repository.importRulesRepositoryFromStream( in );
         
         //
         //Migrate v4 ruleflows to v5

Modified: labs/jbossrules/trunk/drools-guvnor/src/main/java/org/drools/guvnor/server/files/RepositoryBackupServlet.java
===================================================================
--- labs/jbossrules/trunk/drools-guvnor/src/main/java/org/drools/guvnor/server/files/RepositoryBackupServlet.java	2009-02-26 04:53:09 UTC (rev 25428)
+++ labs/jbossrules/trunk/drools-guvnor/src/main/java/org/drools/guvnor/server/files/RepositoryBackupServlet.java	2009-02-26 06:49:19 UTC (rev 25429)
@@ -19,6 +19,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
+import java.util.zip.ZipOutputStream;
+import java.util.zip.ZipEntry;
 
 import javax.jcr.PathNotFoundException;
 import javax.jcr.RepositoryException;
@@ -108,12 +110,12 @@
 				"inline; filename=repository_export.zip;");
 
         System.err.println("Starting to process export");
-        byte[] data = getFileManager().exportRulesRepository();
-        System.err.println(data.length);
-        res.setContentLength(data.length);
-		res.getOutputStream().write(data);
+        ZipOutputStream zout = new ZipOutputStream(res.getOutputStream());
+        zout.putNextEntry(new ZipEntry("repository_export.xml"));
+        getFileManager().exportRulesRepository(zout);
+        zout.closeEntry();
+        zout.finish();
 		res.getOutputStream().flush();
-        System.err.println("Done writing!");
         System.err.println("Done exporting!");
 	}
 
@@ -130,9 +132,7 @@
 	}
 
 	private String processImportRepository(InputStream file) throws IOException {
-		byte[] byteArray = new byte[file.available()];
-		file.read(byteArray);
-		getFileManager().importRulesRepository(byteArray);
+		getFileManager().importRulesRepository(file);
 		return "OK";
 	}
 

Modified: labs/jbossrules/trunk/drools-guvnor/src/test/java/org/drools/guvnor/server/util/FileManagerUtilsTest.java
===================================================================
--- labs/jbossrules/trunk/drools-guvnor/src/test/java/org/drools/guvnor/server/util/FileManagerUtilsTest.java	2009-02-26 04:53:09 UTC (rev 25428)
+++ labs/jbossrules/trunk/drools-guvnor/src/test/java/org/drools/guvnor/server/util/FileManagerUtilsTest.java	2009-02-26 06:49:19 UTC (rev 25429)
@@ -109,14 +109,7 @@
 	}
 
 
-	public void testUploadXmlFile() throws Exception {
-		RulesRepository repo = new RulesRepository(session);
 
-		repo.createPackage("testUploadXmlFile", "comment");
-		repo.importRulesRepository(repo.dumpRepositoryXml());
-		assertTrue(repo.containsPackage("testUploadXmlFile"));
-	}
-
 	public void testGetFilebyUUID() throws Exception {
 		FileManagerUtils uploadHelper = new FileManagerUtils();
 		RulesRepository repo = new RulesRepository(session);

Modified: labs/jbossrules/trunk/drools-repository/src/main/java/org/drools/repository/RulesRepository.java
===================================================================
--- labs/jbossrules/trunk/drools-repository/src/main/java/org/drools/repository/RulesRepository.java	2009-02-26 04:53:09 UTC (rev 25428)
+++ labs/jbossrules/trunk/drools-repository/src/main/java/org/drools/repository/RulesRepository.java	2009-02-26 06:49:19 UTC (rev 25429)
@@ -1,9 +1,6 @@
 package org.drools.repository;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Iterator;
@@ -911,20 +908,22 @@
                                           numRowsToReturn );
     }
 
-    public byte[] exportRulesRepository() throws IOException,
-                                         PathNotFoundException,
-                                         RepositoryException {
+    public void exportRulesRepositoryToStream(OutputStream output) {
+        try {
+            session.refresh( false );
+            session.exportSystemView( "/" + RULES_REPOSITORY_NAME,
+                                      output,
+                                      false,
+                                      false );
+        } catch (Exception e) {
+            log.error(e);
+            e.printStackTrace();
+        }
 
-        ByteArrayOutputStream bout = new ByteArrayOutputStream();
-        ZipOutputStream zout = new ZipOutputStream( bout );
-
-        zout.putNextEntry( new ZipEntry( "repository_export.xml" ) );
-        zout.write( dumpRepositoryXml() );
-        zout.closeEntry();
-        zout.finish();
-        return bout.toByteArray();
     }
 
+
+
     public byte[] exportPackageFromRepository(String packageName) throws IOException,
                                                                  PathNotFoundException,
                                                                  RepositoryException {
@@ -939,18 +938,8 @@
         return bout.toByteArray();
     }
 
-    public byte[] dumpRepositoryXml() throws PathNotFoundException,
-                                     IOException,
-                                     RepositoryException {
-        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
-        session.refresh( false );
-        session.exportSystemView( "/" + RULES_REPOSITORY_NAME,
-                                  byteOut,
-                                  false,
-                                  false );
-        return byteOut.toByteArray();
-    }
 
+
     public byte[] dumpPackageFromRepositoryXml(String packageName) throws PathNotFoundException,
                                                                   IOException,
                                                                   RepositoryException {
@@ -979,15 +968,16 @@
 		}
     }
 
+    
     /**
      * Clean and import the rules repository.
      * Will run any needed migrations as well.
      */
-    public void importRulesRepository(byte[] byteArray) {
+    public void importRulesRepositoryFromStream(InputStream instream) {
         try {
             new RulesRepositoryAdministrator( this.session ).clearRulesRepository();
             this.session.getWorkspace().importXML( "/",
-                                                   new ByteArrayInputStream( byteArray ),
+                                                   instream,
                                                    ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW );
             session.save();
             MigrateDroolsPackage mig = new MigrateDroolsPackage();
@@ -1002,6 +992,8 @@
         }
     }
 
+
+
     public void importPackageToRepository(byte[] byteArray,
                                           boolean importAsNew) {
         try {

Modified: labs/jbossrules/trunk/drools-repository/src/test/java/org/drools/repository/RulesRepositoryTest.java
===================================================================
--- labs/jbossrules/trunk/drools-repository/src/test/java/org/drools/repository/RulesRepositoryTest.java	2009-02-26 04:53:09 UTC (rev 25428)
+++ labs/jbossrules/trunk/drools-repository/src/test/java/org/drools/repository/RulesRepositoryTest.java	2009-02-26 06:49:19 UTC (rev 25429)
@@ -2,6 +2,7 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashMap;
@@ -1045,15 +1046,23 @@
 
         try {
 
-            repository_backup = repo.dumpRepositoryXml();
+            ByteArrayOutputStream bout = new ByteArrayOutputStream();
+            repo.exportRulesRepositoryToStream(bout);
+            repository_backup = bout.toByteArray();
             assertNotNull( repository_backup );
 
             repo.createPackage( "testImportExport",
                                 "nodescription" );
-            repository_unitest = repo.dumpRepositoryXml();
-            repo.importRulesRepository( repository_backup );
+            bout = new ByteArrayOutputStream();
+            repo.exportRulesRepositoryToStream(bout);
+
+            repository_unitest = bout.toByteArray();
+            
+            repo.importRulesRepositoryFromStream(new ByteArrayInputStream(repository_backup));
             assertFalse( repo.containsPackage( "testImportExport" ) );
-            repo.importRulesRepository( repository_unitest );
+
+            repo.importRulesRepositoryFromStream(new ByteArrayInputStream(repository_unitest));
+
             assertTrue( repo.containsPackage( "testImportExport" ) );
 
             repo.importRepository(new ByteArrayInputStream(repository_unitest));
@@ -1065,24 +1074,8 @@
         }
     }
 
-    public void testExportZippedRepository() throws PathNotFoundException,
-                                            IOException,
-                                            RepositoryException {
 
-        RulesRepository repo = RepositorySessionUtil.getRepository();
-        byte[] repository_unitest;
 
-        repository_unitest = repo.exportRulesRepository();
-
-        ByteArrayInputStream bin = new ByteArrayInputStream( repository_unitest );
-        ZipInputStream zis = new ZipInputStream( bin );
-
-        ZipEntry entry = zis.getNextEntry();
-        assertEquals( entry.getName(),
-                      "repository_export.xml" );
-        assertFalse( entry.isDirectory() );
-    }
-
     public static <T> List<T> iteratorToList(Iterator<T> it) {
         List<T> list = new ArrayList<T>();
         while ( it.hasNext() ) {




More information about the jboss-svn-commits mailing list