Author: tsurdilovic
Date: 2009-06-09 22:19:48 -0400 (Tue, 09 Jun 2009)
New Revision: 11103
Added:
branches/community/Seam_2_1/examples/drools/resources/numberguess.xls
branches/community/Seam_2_1/examples/drools/src/org/jboss/seam/example/numberguess/GameConsequenceExceptionHandler.java
branches/community/Seam_2_1/seam-gen/ivy/.ivy.xml.swp
Modified:
branches/community/Seam_2_1/build/core.pom.xml
branches/community/Seam_2_1/build/root.pom.xml
branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/Drools.xml
branches/community/Seam_2_1/examples/build.xml
branches/community/Seam_2_1/examples/drools/resources/WEB-INF/components.xml
branches/community/Seam_2_1/seam-gen/ivy/ivy.xml
branches/community/Seam_2_1/src/main/org/jboss/seam/drools-2.1.xsd
branches/community/Seam_2_1/src/main/org/jboss/seam/drools/ManagedWorkingMemory.java
branches/community/Seam_2_1/src/main/org/jboss/seam/drools/RuleBase.java
Log:
JBSEAM-4049 - Drools Custom Consequence Exception handlers
JBSEAM-4188 - Add decision table support to org.jboss.seam.drools.RuleBase
JBSEAM-4225 - Allow to add eventListeners to WorkingMemory
Modified: branches/community/Seam_2_1/build/core.pom.xml
===================================================================
--- branches/community/Seam_2_1/build/core.pom.xml 2009-06-09 19:18:53 UTC (rev 11102)
+++ branches/community/Seam_2_1/build/core.pom.xml 2009-06-10 02:19:48 UTC (rev 11103)
@@ -252,6 +252,18 @@
<optional>true</optional>
</dependency>
+ <dependency>
+ <groupId>org.drools</groupId>
+ <artifactId>drools-decisiontables</artifactId>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>net.sourceforge.jexcelapi</groupId>
+ <artifactId>jxl</artifactId>
+ <optional>true</optional>
+ </dependency>
+
<!-- Surefire can't cope with such a new version of testng, so we have to
specify it
here, otherwise ui build fails -->
<dependency>
Modified: branches/community/Seam_2_1/build/root.pom.xml
===================================================================
--- branches/community/Seam_2_1/build/root.pom.xml 2009-06-09 19:18:53 UTC (rev 11102)
+++ branches/community/Seam_2_1/build/root.pom.xml 2009-06-10 02:19:48 UTC (rev 11103)
@@ -785,6 +785,12 @@
</exclusion>
</exclusions>
</dependency>
+
+ <dependency>
+ <groupId>org.drools</groupId>
+ <artifactId>drools-decisiontables</artifactId>
+ <version>${version.drools}</version>
+ </dependency>
<dependency>
<groupId>org.drools</groupId>
Modified: branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/Drools.xml
===================================================================
--- branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/Drools.xml 2009-06-09
19:18:53 UTC (rev 11102)
+++ branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/Drools.xml 2009-06-10
02:19:48 UTC (rev 11103)
@@ -26,7 +26,7 @@
</drools:rule-base>]]></programlisting>
<para>
- This component compiles rules from a set of
<literal>.drl</literal>
+ This component compiles rules from a set of DRL
(<literal>.drl</literal>) or decision table
(<literal>.xls</literal>)
files and caches an instance of
<literal>org.drools.RuleBase</literal>
in the Seam <literal>APPLICATION</literal> context. Note that it
is
quite likely that you will need to install multiple rule bases in a
@@ -34,7 +34,7 @@
</para>
<para>
- If you want to use a Drools DSL, you alse need to specify the DSL
+ If you want to use a Drools DSL, you also need to specify the DSL
definition:
</para>
@@ -44,6 +44,40 @@
</drools:rule-files>
</drools:rule-base>]]></programlisting>
+ <para>
+ If you want to register a custom consequence exception handler through the
RuleBaseConfiguration, you need to
+ write the handler, for example:
+ </para>
+
+ <programlisting
role="JAVA"><![CDATA[(a)Scope(ScopeType.APPLICATION)
+@Startup
+@Name("myConsequenceExceptionHandler")
+public class MyConsequenceExceptionHandler implements ConsequenceExceptionHandler,
Externalizable {
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ }
+
+ public void handleException(Activation activation,
+ WorkingMemory workingMemory,
+ Exception exception) {
+ throw new ConsequenceException( exception,
+ activation.getRule() );
+ }
+
+}]]></programlisting>
+
+ <para>
+ and register it:
+ </para>
+ <programlisting role="XML"><![CDATA[<drools:rule-base
name="policyPricingRules" dsl-file="policyPricing.dsl"
consequence-exception-handler="#{myConsequenceExceptionHandler}">
+ <drools:rule-files>
+ <value>policyPricingRules.drl</value>
+ </drools:rule-files>
+</drools:rule-base>]]></programlisting>
+
<para>
In most rules-driven applications,
rules need to be dynamically deployable, so a production application will
want to use a
@@ -87,6 +121,18 @@
configuration property.
</para>
+ <para>
+ We can also add means to be notified of rule engine events, including rules
firing, objects being asserted, etc.
+ by adding event listeners to WorkingMemory.
+ </para>
+
+ <programlisting
role="XML"><![CDATA[<drools:managed-working-memory
name="policyPricingWorkingMemory" auto-create="true"
rule-base="#{policyPricingRules}">
+ <drools:event-listeners>
+ <value>org.drools.event.DebugWorkingMemoryEventListener</value>
+ <value>org.drools.event.DebugAgendaEventListener</value>
+ </drools:event-listeners>
+</drools:managed-working-memory>]]></programlisting>
+
</section>
<section>
Modified: branches/community/Seam_2_1/examples/build.xml
===================================================================
--- branches/community/Seam_2_1/examples/build.xml 2009-06-09 19:18:53 UTC (rev 11102)
+++ branches/community/Seam_2_1/examples/build.xml 2009-06-10 02:19:48 UTC (rev 11103)
@@ -325,6 +325,8 @@
<include name="mvel14.jar" if="drools.lib" />
<include name="drools-core.jar" if="drools.lib" />
<include name="drools-compiler.jar" if="drools.lib" />
+ <include name="drools-decisiontables.jar" if="drools.lib"/>
+ <include name="jxl.jar" if="drools.lib"/>
</fileset>
<!-- Dependencies for using Spring with Cglib -->
@@ -470,6 +472,11 @@
<include name="*.jpdl.xml" />
<exclude name=".gpd*" />
</fileset>
+
+ <!-- binary resources to go in the jar -->
+ <fileset id="jar.binary.resources" dir="${resources.dir}">
+ <include name="*.xls" />
+ </fileset>
<!-- resources to go in the jar for tomcat -->
<fileset id="tomcat.jar.resources" dir="${resources.dir}">
@@ -652,6 +659,11 @@
<filter token="distributable" value="${distributable}" />
</filterset>
</copy>
+ <!-- copy decision tables (binary) without the filter definitions
+ so that they won't get corrupted -->
+ <copy todir="${jar.dir}">
+ <fileset refid="jar.binary.resources" />
+ </copy>
</target>
<target name="init.war">
Modified: branches/community/Seam_2_1/examples/drools/resources/WEB-INF/components.xml
===================================================================
---
branches/community/Seam_2_1/examples/drools/resources/WEB-INF/components.xml 2009-06-09
19:18:53 UTC (rev 11102)
+++
branches/community/Seam_2_1/examples/drools/resources/WEB-INF/components.xml 2009-06-10
02:19:48 UTC (rev 11103)
@@ -10,7 +10,17 @@
http://jboss.com/products/seam/bpm
http://jboss.com/products/seam/bpm-2.1.xsd">
<drools:rule-base name="ruleBase"
rule-files="numberguess.drl"/>
- <drools:managed-working-memory name="workingMemory"
rule-base="#{ruleBase}"/>
+ <!-- use this in order to load from decision table instead -->
+ <!-- <drools:rule-base name="ruleBase"
rule-files="numberguess.xls"/> -->
+ <!-- use this if you want to register a custom consequence exception handler
-->
+ <!-- <drools:rule-base name="ruleBase"
rule-files="numberguess.drl"
consequence-exception-handler="#{gameConsequenceExceptionHandler}"/> -->
+ <drools:managed-working-memory name="workingMemory"
rule-base="#{ruleBase}">
+ <!-- add WM event listeners -->
+ <!-- <drools:event-listeners>
+ <value>org.drools.event.DebugWorkingMemoryEventListener</value>
+ <value>org.drools.event.DebugAgendaEventListener</value>
+ </drools:event-listeners> -->
+ </drools:managed-working-memory>
<bpm:jbpm>
<bpm:pageflow-definitions>
Added: branches/community/Seam_2_1/examples/drools/resources/numberguess.xls
===================================================================
(Binary files differ)
Property changes on:
branches/community/Seam_2_1/examples/drools/resources/numberguess.xls
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added:
branches/community/Seam_2_1/examples/drools/src/org/jboss/seam/example/numberguess/GameConsequenceExceptionHandler.java
===================================================================
---
branches/community/Seam_2_1/examples/drools/src/org/jboss/seam/example/numberguess/GameConsequenceExceptionHandler.java
(rev 0)
+++
branches/community/Seam_2_1/examples/drools/src/org/jboss/seam/example/numberguess/GameConsequenceExceptionHandler.java 2009-06-10
02:19:48 UTC (rev 11103)
@@ -0,0 +1,36 @@
+package org.jboss.seam.example.numberguess;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.drools.WorkingMemory;
+import org.drools.spi.Activation;
+import org.drools.spi.ConsequenceException;
+import org.drools.spi.ConsequenceExceptionHandler;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Startup;
+
+(a)Scope(ScopeType.APPLICATION)
+@Startup
+@Name("gameConsequenceExceptionHandler")
+public class GameConsequenceExceptionHandler implements ConsequenceExceptionHandler,
Externalizable {
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ }
+
+ public void handleException(Activation activation,
+ WorkingMemory workingMemory,
+ Exception exception) {
+ throw new ConsequenceException( exception,
+ activation.getRule() );
+ }
+
+}
+
Added: branches/community/Seam_2_1/seam-gen/ivy/.ivy.xml.swp
===================================================================
(Binary files differ)
Property changes on: branches/community/Seam_2_1/seam-gen/ivy/.ivy.xml.swp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: branches/community/Seam_2_1/seam-gen/ivy/ivy.xml
===================================================================
--- branches/community/Seam_2_1/seam-gen/ivy/ivy.xml 2009-06-09 19:18:53 UTC (rev 11102)
+++ branches/community/Seam_2_1/seam-gen/ivy/ivy.xml 2009-06-10 02:19:48 UTC (rev 11103)
@@ -56,6 +56,9 @@
<dependency org="org.drools" name="drools-core"
rev="4.0.4">
<artifact name="drools-core" type="jar"/>
</dependency>
+ <dependency org="org.drools" name="drools-decisiontables"
rev="4.0.4">
+ <artifact name="drools-decisiontables"
type="jar"/>
+ </dependency>
<dependency org="org.eclipse.jdt" name="core"
rev="3.2.3.v_686_R32x">
<artifact name="core" type="jar"/>
</dependency>
Modified:
branches/community/Seam_2_1/src/main/org/jboss/seam/drools/ManagedWorkingMemory.java
===================================================================
---
branches/community/Seam_2_1/src/main/org/jboss/seam/drools/ManagedWorkingMemory.java 2009-06-09
19:18:53 UTC (rev 11102)
+++
branches/community/Seam_2_1/src/main/org/jboss/seam/drools/ManagedWorkingMemory.java 2009-06-10
02:19:48 UTC (rev 11103)
@@ -4,6 +4,9 @@
import org.drools.RuleBase;
import org.drools.StatefulSession;
+import org.drools.event.AgendaEventListener;
+import org.drools.event.RuleFlowEventListener;
+import org.drools.event.WorkingMemoryEventListener;
import org.drools.spi.GlobalResolver;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
@@ -13,6 +16,8 @@
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.core.Mutable;
import org.jboss.seam.core.Expressions.ValueExpression;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
/**
* A conversation-scoped Drools WorkingMemory for a named RuleBase
@@ -26,7 +31,10 @@
{
private static final long serialVersionUID = -1746942080571374743L;
+ private static final LogProvider log =
Logging.getLogProvider(ManagedWorkingMemory.class);
+
private String ruleBaseName;
+ private String[] eventListeners;
private StatefulSession statefulSession;
private ValueExpression<RuleBase> ruleBase;
@@ -66,9 +74,44 @@
{
statefulSession = getRuleBaseFromValueBinding().newStatefulSession();
statefulSession.setGlobalResolver( createGlobalResolver(
statefulSession.getGlobalResolver() ) );
+ if(eventListeners != null) {
+ setEventListeners(statefulSession);
+ }
}
return statefulSession;
}
+
+ private void setEventListeners(StatefulSession statefulSession) {
+ if(eventListeners != null) {
+ for(String eventListener : eventListeners) {
+ log.debug("adding eventListener: " + eventListener);
+ try
+ {
+ Class eventListenerClass = Class.forName(eventListener);
+ Object eventListenerObject = eventListenerClass.newInstance();
+ if(eventListenerObject instanceof WorkingMemoryEventListener)
+ {
+ statefulSession.addEventListener((WorkingMemoryEventListener)
eventListenerObject);
+ }
+ else if(eventListenerObject instanceof AgendaEventListener)
+ {
+ statefulSession.addEventListener((AgendaEventListener)
eventListenerObject);
+ }
+ else if(eventListenerObject instanceof RuleFlowEventListener)
+ {
+ statefulSession.addEventListener((RuleFlowEventListener)
eventListenerObject);
+ }
+ else {
+ log.debug("event Listener is not of valid type -
bypassing.");
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("error adding event listener " + eventListener +
" - bypassing.");
+ }
+ }
+ }
+ }
protected RuleBase getRuleBaseFromValueBinding()
{
@@ -114,5 +157,17 @@
{
this.ruleBase = ruleBase;
}
+
+ public String[] getEventListeners()
+ {
+ return eventListeners;
+ }
+
+ public void setEventListeners(String[] eventListeners)
+ {
+ this.eventListeners = eventListeners;
+ }
+
+
}
Modified: branches/community/Seam_2_1/src/main/org/jboss/seam/drools/RuleBase.java
===================================================================
--- branches/community/Seam_2_1/src/main/org/jboss/seam/drools/RuleBase.java 2009-06-09
19:18:53 UTC (rev 11102)
+++ branches/community/Seam_2_1/src/main/org/jboss/seam/drools/RuleBase.java 2009-06-10
02:19:48 UTC (rev 11103)
@@ -1,20 +1,26 @@
package org.jboss.seam.drools;
+import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import org.drools.RuleBaseConfiguration;
import org.drools.RuleBaseFactory;
import org.drools.compiler.DroolsError;
import org.drools.compiler.PackageBuilder;
import org.drools.compiler.PackageBuilderConfiguration;
import org.drools.compiler.RuleError;
+import org.drools.decisiontable.InputType;
+import org.drools.decisiontable.SpreadsheetCompiler;
+import org.drools.spi.ConsequenceExceptionHandler;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Unwrap;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.core.ResourceLoader;
+import org.jboss.seam.core.Expressions.ValueExpression;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
@@ -32,6 +38,7 @@
private String[] ruleFiles;
private String dslFile;
+ private ValueExpression<ConsequenceExceptionHandler>
consequenceExceptionHandler;
private org.drools.RuleBase ruleBase;
@Create
@@ -50,18 +57,32 @@
{
throw new IllegalStateException("could not locate rule file: " +
ruleFile);
}
- // read in the source
- Reader drlReader = new InputStreamReader(stream);
-
- if (dslFile==null)
+
+ if(isDecisionTable(ruleFile))
{
- builder.addPackageFromDrl(drlReader);
+ log.debug("compiling decision table");
+ SpreadsheetCompiler compiler = new SpreadsheetCompiler();
+ String drl = compiler.compile(stream, InputType.XLS);
+
+ log.debug("creating source");
+ byte currentXMLBytes[] = drl.getBytes();
+ InputStreamReader source = new InputStreamReader(new
ByteArrayInputStream(currentXMLBytes));
+
+ builder.addPackageFromDrl(source);
+ } else {
+ // read in the source
+ Reader drlReader = new InputStreamReader(stream);
+
+ if (dslFile==null)
+ {
+ builder.addPackageFromDrl(drlReader);
+ }
+ else
+ {
+ Reader dslReader = new InputStreamReader(
ResourceLoader.instance().getResourceAsStream(dslFile) );
+ builder.addPackageFromDrl(drlReader, dslReader);
+ }
}
- else
- {
- Reader dslReader = new InputStreamReader(
ResourceLoader.instance().getResourceAsStream(dslFile) );
- builder.addPackageFromDrl(drlReader, dslReader);
- }
if ( builder.hasErrors() )
{
@@ -82,8 +103,19 @@
}
}
- // add the package to a rulebase
- ruleBase = RuleBaseFactory.newRuleBase();
+
+ if(consequenceExceptionHandler != null)
+ {
+ log.info("adding consequence exception handler: " +
consequenceExceptionHandler.getExpressionString());
+ RuleBaseConfiguration rbconf = new RuleBaseConfiguration();
+ rbconf.setConsequenceExceptionHandler(consequenceExceptionHandler.getValue());
+ ruleBase = RuleBaseFactory.newRuleBase( rbconf );
+ }
+ else
+ {
+ ruleBase = RuleBaseFactory.newRuleBase();
+ }
+
ruleBase.addPackage( builder.getPackage() );
}
@@ -113,4 +145,18 @@
this.dslFile = dslFile;
}
+ public ValueExpression<ConsequenceExceptionHandler>
getConsequenceExceptionHandler()
+ {
+ return consequenceExceptionHandler;
+ }
+
+ public void
setConsequenceExceptionHandler(ValueExpression<ConsequenceExceptionHandler>
consequenceExceptionHandler)
+ {
+ this.consequenceExceptionHandler = consequenceExceptionHandler;
+ }
+
+ private boolean isDecisionTable(String fileName)
+ {
+ return fileName != null && fileName.length() > 0 &&
fileName.endsWith(".xls");
+ }
}
Modified: branches/community/Seam_2_1/src/main/org/jboss/seam/drools-2.1.xsd
===================================================================
--- branches/community/Seam_2_1/src/main/org/jboss/seam/drools-2.1.xsd 2009-06-09 19:18:53
UTC (rev 11102)
+++ branches/community/Seam_2_1/src/main/org/jboss/seam/drools-2.1.xsd 2009-06-10 02:19:48
UTC (rev 11103)
@@ -11,8 +11,8 @@
</xs:annotation>
<xs:complexType mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element minOccurs="0" maxOccurs="1"
ref="drools:rule-files"/>
- </xs:choice>
+ <xs:element minOccurs="0" maxOccurs="1"
ref="drools:rule-files"/>
+ </xs:choice>
<xs:attributeGroup ref="components:attlist.component"/>
<xs:attributeGroup ref="drools:attlist.RuleBase"/>
</xs:complexType>
@@ -20,8 +20,10 @@
<xs:element name="rule-files"
type="components:multiValuedProperty"/>
<xs:attributeGroup name="attlist.RuleBase">
<xs:attribute name="dsl-file"
type="components:string"/>
- <xs:attribute name="rule-files"
type="components:string"/>
+ <xs:attribute name="rule-files"
type="components:string"/>
+ <xs:attribute name="consequence-exception-handler"
type="components:expressionType"/>
</xs:attributeGroup>
+
<xs:element name="rule-agent">
<xs:annotation>
@@ -47,6 +49,9 @@
<xs:documentation>A working memory for rules
calculations</xs:documentation>
</xs:annotation>
<xs:complexType mixed="true">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element minOccurs="0" maxOccurs="1"
ref="drools:event-listeners"/>
+ </xs:choice>
<xs:attributeGroup ref="components:attlist.component"/>
<xs:attributeGroup
ref="drools:attlist.ManagedWorkingMemory"/>
</xs:complexType>
@@ -54,5 +59,6 @@
<xs:attributeGroup name="attlist.ManagedWorkingMemory">
<xs:attribute name="rule-base"
type="components:expressionType"/>
</xs:attributeGroup>
+ <xs:element name="event-listeners"
type="components:multiValuedProperty"/>
</xs:schema>