[jboss-svn-commits] JBL Code SVN: r15775 - in labs/jbossrules/branches/Branch_4_0_2_SOA_4_2: drools-compiler/src/test/java/org/drools/integrationtests and 2 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Thu Oct 11 14:49:52 EDT 2007
Author: fmeyer
Date: 2007-10-11 14:49:52 -0400 (Thu, 11 Oct 2007)
New Revision: 15775
Modified:
labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/Message.java
labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/integrationtests/ExecutionFlowControlTest.java
labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java
labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/HelloWorld.drl
labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/test_EffectiveDate.drl
labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/test_ExplicitAnd.drl
labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-core/src/main/java/org/drools/reteoo/CompositeObjectSinkAdapter.java
Log:
[JBRULES-1264] NPE at BaseObjectClassFieldExtractor.getLongValue with null fields
Modified: labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/Message.java
===================================================================
--- labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/Message.java 2007-10-11 18:45:10 UTC (rev 15774)
+++ labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/Message.java 2007-10-11 18:49:52 UTC (rev 15775)
@@ -1,67 +1,119 @@
-/**
- *
- */
-package org.drools;
-
-public class Message {
-
- private String message1 = "One";
- private String message2 = "Two";
- private String message3 = "Three";
- private String message4 = "Four";
-
- public static final int HELLO = 0;
- public static final int GOODBYE = 1;
-
- private String message;
-
- private int status;
-
- public String getMessage() {
- return this.message;
- }
-
- public void setMessage(final String message) {
- this.message = message;
- }
-
- public int getStatus() {
- return this.status;
- }
-
- public void setStatus(final int status) {
- this.status = status;
- }
-
- public String getMessage1() {
- return this.message1;
- }
-
- public void setMessage1(final String message1) {
- this.message1 = message1;
- }
-
- public String getMessage2() {
- return this.message2;
- }
-
- public void setMessage2(final String message2) {
- this.message2 = message2;
- }
-
- public String getMessage3() {
- return this.message3;
- }
-
- public void setMessage3(final String message3) {
- this.message3 = message3;
- }
-
- public String getMessage4() {
- return this.message4;
- }
-
- public void setMessage4(final String message4) {
- this.message4 = message4;
- }
+/**
+ *
+ */
+package org.drools;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class Message {
+
+ private String message1 = "One";
+ private String message2 = "Two";
+ private String message3 = "Three";
+ private String message4 = "Four";
+
+ public static final int HELLO = 0;
+ public static final int GOODBYE = 1;
+
+ private String message;
+
+ private int status;
+
+ private List list = new ArrayList();
+ private int number = 0;
+ private Date birthday = new Date();
+ private boolean fired = false;
+
+ public Message() {
+ }
+
+ public Message(final String msg) {
+ this.message = msg;
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+
+ public void setMessage(final String message) {
+ this.message = message;
+ }
+
+ public int getStatus() {
+ return this.status;
+ }
+
+ public void setStatus(final int status) {
+ this.status = status;
+ }
+
+ public String getMessage1() {
+ return this.message1;
+ }
+
+ public void setMessage1(final String message1) {
+ this.message1 = message1;
+ }
+
+ public String getMessage2() {
+ return this.message2;
+ }
+
+ public void setMessage2(final String message2) {
+ this.message2 = message2;
+ }
+
+ public String getMessage3() {
+ return this.message3;
+ }
+
+ public void setMessage3(final String message3) {
+ this.message3 = message3;
+ }
+
+ public String getMessage4() {
+ return this.message4;
+ }
+
+ public void setMessage4(final String message4) {
+ this.message4 = message4;
+ }
+
+ public boolean isFired() {
+ return this.fired;
+ }
+
+ public void setFired(final boolean fired) {
+ this.fired = fired;
+ }
+
+ public Date getBirthday() {
+ return this.birthday;
+ }
+
+ public void setBirthday(final Date birthday) {
+ this.birthday = birthday;
+ }
+
+ public int getNumber() {
+ return this.number;
+ }
+
+ public void setNumber(final int number) {
+ this.number = number;
+ }
+
+ public List getList() {
+ return this.list;
+ }
+
+ public void setList(final List list) {
+ this.list = list;
+ }
+
+ public void addToList(final String s) {
+ this.list.add( s );
+ }
}
\ No newline at end of file
Modified: labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/integrationtests/ExecutionFlowControlTest.java
===================================================================
--- labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/integrationtests/ExecutionFlowControlTest.java 2007-10-11 18:45:10 UTC (rev 15774)
+++ labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/integrationtests/ExecutionFlowControlTest.java 2007-10-11 18:49:52 UTC (rev 15775)
@@ -1,780 +1,780 @@
-package org.drools.integrationtests;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
-
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
-import org.drools.Cheese;
-import org.drools.FactHandle;
-import org.drools.Person;
-import org.drools.PersonInterface;
-import org.drools.RuleBase;
-import org.drools.RuleBaseConfiguration;
-import org.drools.RuleBaseFactory;
-import org.drools.WorkingMemory;
-import org.drools.common.DefaultAgenda;
-import org.drools.common.InternalWorkingMemoryActions;
-import org.drools.common.RuleFlowGroupImpl;
-import org.drools.compiler.DrlParser;
-import org.drools.compiler.DroolsParserException;
-import org.drools.compiler.PackageBuilder;
-import org.drools.compiler.ProcessBuilder;
-import org.drools.compiler.PackageBuilder.PackageMergeException;
-import org.drools.event.ActivationCancelledEvent;
-import org.drools.event.ActivationCreatedEvent;
-import org.drools.event.AgendaEventListener;
-import org.drools.event.DefaultAgendaEventListener;
-import org.drools.integrationtests.helloworld.Message;
-import org.drools.lang.descr.PackageDescr;
-import org.drools.rule.Package;
-import org.drools.ruleflow.common.instance.ProcessInstance;
-import org.drools.spi.Activation;
-import org.drools.spi.ActivationGroup;
-import org.drools.spi.AgendaGroup;
-
-public class ExecutionFlowControlTest extends TestCase {
- protected RuleBase getRuleBase() throws Exception {
-
- return RuleBaseFactory.newRuleBase( RuleBase.RETEOO,
- null );
- }
-
- protected RuleBase getRuleBase(final RuleBaseConfiguration config) throws Exception {
-
- return RuleBaseFactory.newRuleBase( RuleBase.RETEOO,
- config );
- }
-
- public void testSalienceInteger() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_salienceIntegerRule.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- final PersonInterface person = new Person( "Edson",
- "cheese" );
- workingMemory.insert( person );
-
- workingMemory.fireAllRules();
-
- Assert.assertEquals( "Two rules should have been fired",
- 2,
- list.size() );
- Assert.assertEquals( "Rule 3 should have been fired first",
- "Rule 3",
- list.get( 0 ) );
- Assert.assertEquals( "Rule 2 should have been fired second",
- "Rule 2",
- list.get( 1 ) );
- }
-
- public void testSalienceExpression() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_salienceExpressionRule.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- final PersonInterface person10 = new Person( "bob",
- "cheese",
- 10);
- workingMemory.insert( person10 );
-
- final PersonInterface person20 = new Person( "mic",
- "cheese",
- 20);
- workingMemory.insert( person20 );
-
- workingMemory.fireAllRules();
-
- Assert.assertEquals( "Two rules should have been fired",
- 2,
- list.size() );
- Assert.assertEquals( "Rule 3 should have been fired first",
- "Rule 3",
- list.get( 0 ) );
- Assert.assertEquals( "Rule 2 should have been fired second",
- "Rule 2",
- list.get( 1 ) );
- }
-
- public void testNoLoop() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "no-loop.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- final Cheese brie = new Cheese( "brie",
- 12 );
- workingMemory.insert( brie );
-
- workingMemory.fireAllRules();
-
- Assert.assertEquals( "Should not loop and thus size should be 1",
- 1,
- list.size() );
-
- }
-
- public void testLockOnActive() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LockOnActive.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- // AgendaGroup "group1" is not active, so should receive activation
- final Cheese brie12 = new Cheese( "brie",
- 12 );
- workingMemory.insert( brie12 );
- final AgendaGroup group1 = workingMemory.getAgenda().getAgendaGroup( "group1" );
- assertEquals( 1,
- group1.size() );
-
- workingMemory.setFocus( "group1" );
- // AgendaqGroup "group1" is now active, so should not receive activations
- final Cheese brie10 = new Cheese( "brie",
- 10 );
- workingMemory.insert( brie10 );
- assertEquals( 1,
- group1.size() );
-
- final Cheese cheddar20 = new Cheese( "cheddar",
- 20 );
- workingMemory.insert( cheddar20 );
- final AgendaGroup group2 = workingMemory.getAgenda().getAgendaGroup( "group1" );
- assertEquals( 1,
- group2.size() );
-
- final RuleFlowGroupImpl rfg = (RuleFlowGroupImpl) workingMemory.getAgenda().getRuleFlowGroup( "ruleflow2" );
- rfg.setActive( true );
- final Cheese cheddar17 = new Cheese( "cheddar",
- 17 );
- workingMemory.insert( cheddar17 );
- assertEquals( 1,
- group2.size() );
- }
-
- public void testLockOnActiveWithModify() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LockOnActiveWithUpdate.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- final WorkingMemory wm = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- wm.setGlobal( "list",
- list );
-
- final Cheese brie = new Cheese( "brie",
- 13 );
-
- final Person bob = new Person( "bob" );
- bob.setCheese( brie );
-
- final Person mic = new Person( "mic" );
- mic.setCheese( brie );
-
- final Person mark = new Person( "mark" );
- mark.setCheese( brie );
-
- final FactHandle brieHandle = wm.insert( brie );
- wm.insert( bob );
- wm.insert( mic );
- wm.insert( mark );
-
- final DefaultAgenda agenda = (DefaultAgenda) wm.getAgenda();
- final AgendaGroup group1 = agenda.getAgendaGroup( "group1" );
- agenda.setFocus( group1 );
- assertEquals( 3,
- group1.size() );
- agenda.fireNextItem( null );
- assertEquals( 2,
- group1.size() );
- wm.update( brieHandle,
- brie );
- assertEquals( 2,
- group1.size() );
-
- AgendaGroup group2 = agenda.getAgendaGroup( "group2" );
- agenda.setFocus( group2 );
-
- RuleFlowGroupImpl rfg = (RuleFlowGroupImpl) wm.getAgenda().getRuleFlowGroup( "ruleflow2" );
- assertEquals( 3,
- rfg.size() );
-
- agenda.activateRuleFlowGroup( "ruleflow2" );
- agenda.fireNextItem( null );
- assertEquals( 2,
- rfg.size() );
- wm.update( brieHandle,
- brie );
- assertEquals( 2,
- group2.size() );
- }
-
- public void testAgendaGroups() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_AgendaGroups.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- final Cheese brie = new Cheese( "brie",
- 12 );
- workingMemory.insert( brie );
-
- workingMemory.fireAllRules();
-
- assertEquals( 7,
- list.size() );
-
- assertEquals( "group3",
- list.get( 0 ) );
- assertEquals( "group4",
- list.get( 1 ) );
- assertEquals( "group3",
- list.get( 2 ) );
- assertEquals( "MAIN",
- list.get( 3 ) );
- assertEquals( "group1",
- list.get( 4 ) );
- assertEquals( "group1",
- list.get( 5 ) );
- assertEquals( "MAIN",
- list.get( 6 ) );
-
- workingMemory.setFocus( "group2" );
- workingMemory.fireAllRules();
-
- assertEquals( 8,
- list.size() );
- assertEquals( "group2",
- list.get( 7 ) );
- }
-
- public void testActivationGroups() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_ActivationGroups.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- final Cheese brie = new Cheese( "brie",
- 12 );
- workingMemory.insert( brie );
-
- final ActivationGroup activationGroup0 = workingMemory.getAgenda().getActivationGroup( "activation-group-0" );
- assertEquals( 2,
- activationGroup0.size() );
-
- final ActivationGroup activationGroup3 = workingMemory.getAgenda().getActivationGroup( "activation-group-3" );
- assertEquals( 1,
- activationGroup3.size() );
-
- final AgendaGroup agendaGroup3 = workingMemory.getAgenda().getAgendaGroup( "agenda-group-3" );
- assertEquals( 1,
- agendaGroup3.size() );
-
- final AgendaGroup agendaGroupMain = workingMemory.getAgenda().getAgendaGroup( "MAIN" );
- assertEquals( 3,
- agendaGroupMain.size() );
-
- workingMemory.clearAgendaGroup( "agenda-group-3" );
- assertEquals( 0,
- activationGroup3.size() );
- assertEquals( 0,
- agendaGroup3.size() );
-
- workingMemory.fireAllRules();
-
- assertEquals( 0,
- activationGroup0.size() );
-
- assertEquals( 2,
- list.size() );
- assertEquals( "rule0",
- list.get( 0 ) );
- assertEquals( "rule2",
- list.get( 1 ) );
-
- }
-
- public void testDuration() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Duration.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- final Cheese brie = new Cheese( "brie",
- 12 );
- final FactHandle brieHandle = workingMemory.insert( brie );
-
- workingMemory.fireAllRules();
-
- // now check for update
- assertEquals( 0,
- list.size() );
-
- // sleep for 300ms
- Thread.sleep( 300 );
-
- // now check for update
- assertEquals( 1,
- list.size() );
-
- }
-
- public void testInsertRetractNoloop() throws Exception {
- // read in the source
- final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_Insert_Retract_Noloop.drl" ) );
- final RuleBase ruleBase = loadRuleBase( reader );
-
- final WorkingMemory wm = ruleBase.newStatefulSession();
- wm.insert( new Cheese( "stilton",
- 15 ) );
-
- wm.fireAllRules();
- }
-
- public void testDurationWithNoLoop() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Duration_with_NoLoop.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- final Cheese brie = new Cheese( "brie",
- 12 );
- final FactHandle brieHandle = workingMemory.insert( brie );
-
- workingMemory.fireAllRules();
-
- // now check for update
- assertEquals( 0,
- list.size() );
-
- // sleep for 300ms
- Thread.sleep( 300 );
-
- // now check for update
- assertEquals( 1,
- list.size() );
- }
-
- public void testFireRuleAfterDuration() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_FireRuleAfterDuration.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- final Cheese brie = new Cheese( "brie",
- 12 );
- final FactHandle brieHandle = workingMemory.insert( brie );
-
- workingMemory.fireAllRules();
-
- // now check for update
- assertEquals( 0,
- list.size() );
-
- // sleep for 300ms
- Thread.sleep( 300 );
-
- workingMemory.fireAllRules();
-
- // now check for update
- assertEquals( 2,
- list.size() );
-
- }
-
- public void testUpdateNoLoop() throws Exception {
- // JBRULES-780, throws a NullPointer or infinite loop if there is an issue
- final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_UpdateNoloop.drl" ) );
- final RuleBase ruleBase = loadRuleBase( reader );
-
- final WorkingMemory wm = ruleBase.newStatefulSession();
- wm.insert( new Cheese( "stilton",
- 15 ) );
-
- wm.fireAllRules();
- }
-
- public void testUpdateActivationCreationNoLoop() throws Exception {
- // JBRULES-787, no-loop blocks all dependant tuples for update
- final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_UpdateActivationCreationNoLoop.drl" ) );
- final RuleBase ruleBase = loadRuleBase( reader );
-
- final InternalWorkingMemoryActions wm = (InternalWorkingMemoryActions) ruleBase.newStatefulSession();
- final List created = new ArrayList();
- final List cancelled = new ArrayList();
- final AgendaEventListener l = new DefaultAgendaEventListener() {
- public void activationCreated(ActivationCreatedEvent event,
- WorkingMemory workingMemory) {
- created.add( event );
- }
-
- public void activationCancelled(ActivationCancelledEvent event,
- WorkingMemory workingMemory) {
- cancelled.add( event );
- }
-
- };
-
- wm.addEventListener( l );
-
- final Cheese stilton = new Cheese( "stilton",
- 15 );
- final FactHandle stiltonHandle = wm.insert( stilton );
-
- final Person p1 = new Person( "p1" );
- p1.setCheese( stilton );
- wm.insert( p1 );
-
- final Person p2 = new Person( "p2" );
- p2.setCheese( stilton );
- wm.insert( p2 );
-
- final Person p3 = new Person( "p3" );
- p3.setCheese( stilton );
- wm.insert( p3 );
-
- assertEquals( 3,
- created.size() );
- assertEquals( 0,
- cancelled.size() );
-
- final Activation item = ((ActivationCreatedEvent) created.get( 2 )).getActivation();
-
- // simulate a modify inside a consequence
- wm.update( stiltonHandle,
- stilton,
- item.getRule(),
- item );
-
- // the two of the three tuples should re-activate
- assertEquals( 5,
- created.size() );
- assertEquals( 3,
- cancelled.size() );
- }
-
- public void testRuleFlowGroup() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflowgroup.drl" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
-
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- workingMemory.insert( "Test" );
- workingMemory.fireAllRules();
- assertEquals( 0,
- list.size() );
-
- workingMemory.getAgenda().activateRuleFlowGroup( "Group1" );
- workingMemory.fireAllRules();
-
- assertEquals( 1,
- list.size() );
- }
-
- public void testRuleFlow() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.drl" ) ) );
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );
- final Package pkg = builder.getPackage();
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
-
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- workingMemory.fireAllRules();
- assertEquals( 0,
- list.size() );
-
- final ProcessInstance processInstance = workingMemory.startProcess( "0" );
- assertEquals( ProcessInstance.STATE_ACTIVE,
- processInstance.getState() );
- workingMemory.fireAllRules();
- assertEquals( 4,
- list.size() );
- assertEquals( "Rule1",
- list.get( 0 ) );
- assertEquals( "Rule3",
- list.get( 1 ) );
- assertEquals( "Rule2",
- list.get( 2 ) );
- assertEquals( "Rule4",
- list.get( 3 ) );
- assertEquals( ProcessInstance.STATE_COMPLETED,
- processInstance.getState() );
- }
-
- public void testRuleFlowClear() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_ruleflowClear.drl" ) ) );
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "test_ruleflowClear.rfm" ) ) );
- final Package pkg = builder.getPackage();
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
-
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- final List activations = new ArrayList();
- AgendaEventListener listener = new DefaultAgendaEventListener() {
- public void activationCancelled(ActivationCancelledEvent event,
- WorkingMemory workingMemory) {
- activations.add( event.getActivation() );
- }
- };
-
- workingMemory.addEventListener( listener );
-
- assertEquals( 0 , workingMemory.getAgenda().getRuleFlowGroup( "flowgroup-1" ).size() );
-
- // We need to call fireAllRules here to get the InitialFact into the system, to the eval(true)'s kick in
- workingMemory.fireAllRules();
-
- // Now we have 4 in the RuleFlow, but not yet in the agenda
- assertEquals( 4 , workingMemory.getAgenda().getRuleFlowGroup( "flowgroup-1" ).size() );
-
- // Check they aren't in the Agenda
- assertEquals( 0, workingMemory.getAgenda().getAgendaGroup( "MAIN" ).size() );
-
- // Start the process, which shoudl populate the Agenda
- final ProcessInstance processInstance = workingMemory.startProcess( "ruleFlowClear" );
- assertEquals( 4, workingMemory.getAgenda().getAgendaGroup( "MAIN" ).size() );
-
-
- // Check we have 0 activation cancellation events
- assertEquals( 0, activations.size() );
-
- workingMemory.getAgenda().clearRuleFlowGroup( "flowgroup-1" );
-
- // Check the AgendaGroup and RuleFlowGroup are now empty
- assertEquals( 0, workingMemory.getAgenda().getAgendaGroup( "MAIN" ).size() );
- assertEquals( 0 , workingMemory.getAgenda().getRuleFlowGroup( "flowgroup-1" ).size() );
-
- // Check we have four activation cancellation events
- assertEquals( 4, activations.size() );
- }
-
- public void testRuleFlowInPackage() throws Exception {
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.drl" ) ) );
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );
- final Package pkg = builder.getPackage();
-
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
-
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- workingMemory.fireAllRules();
- assertEquals( 0,
- list.size() );
-
- final ProcessInstance processInstance = workingMemory.startProcess( "0" );
- assertEquals( ProcessInstance.STATE_ACTIVE,
- processInstance.getState() );
- workingMemory.fireAllRules();
- assertEquals( 4,
- list.size() );
- assertEquals( "Rule1",
- list.get( 0 ) );
- assertEquals( "Rule3",
- list.get( 1 ) );
- assertEquals( "Rule2",
- list.get( 2 ) );
- assertEquals( "Rule4",
- list.get( 3 ) );
- assertEquals( ProcessInstance.STATE_COMPLETED,
- processInstance.getState() );
-
- }
-
- public void testLoadingRuleFlowInPackage1() throws Exception {
- // adding ruleflow before adding package
- final PackageBuilder builder = new PackageBuilder();
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.drl" ) ) );
- builder.getPackage();
- }
-
- public void testLoadingRuleFlowInPackage2() throws Exception {
- // only adding ruleflow
- final PackageBuilder builder = new PackageBuilder();
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );
- builder.getPackage();
- }
-
- public void testLoadingRuleFlowInPackage3() throws Exception {
- // only adding ruleflow without any generated rules
- final PackageBuilder builder = new PackageBuilder();
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "empty_ruleflow.rfm" ) ) );
- builder.getPackage();
- }
-
- public void testLoadingRuleFlowInPackage4() throws Exception {
- // adding ruleflows of different package
- final PackageBuilder builder = new PackageBuilder();
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "empty_ruleflow.rfm" ) ) );
- try {
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );
- throw new Exception("An exception should have been thrown.");
- } catch (PackageMergeException e) {
- // do nothing
- }
- }
-
- public void testLoadingRuleFlowInPackage5() throws Exception {
- // adding ruleflow of different package than rules
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.drl" ) ) );
- try {
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "empty_ruleflow.rfm" ) ) );
- throw new Exception("An exception should have been thrown.");
- } catch (PackageMergeException e) {
- // do nothing
- }
- }
-
- public void testLoadingRuleFlowInPackage6() throws Exception {
- // adding rules of different package than ruleflow
- final PackageBuilder builder = new PackageBuilder();
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "empty_ruleflow.rfm" ) ) );
- try {
- builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.drl" ) ) );
- throw new Exception("An exception should have been thrown.");
- } catch (PackageMergeException e) {
- // do nothing
- }
- }
-
- public void testLoadingRuleFlowInPackage7() throws Exception {
- // loading a ruleflow with errors
- final PackageBuilder builder = new PackageBuilder();
- builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "error_ruleflow.rfm" ) ) );
- assertEquals(1, builder.getErrors().getErrors().length);
- }
-
- private RuleBase loadRuleBase(final Reader reader) throws IOException,
- DroolsParserException,
- Exception {
- final DrlParser parser = new DrlParser();
- final PackageDescr packageDescr = parser.parse( reader );
- if ( parser.hasErrors() ) {
- Assert.fail( "Error messages in parser, need to sort this our (or else collect error messages)" );
- }
- // pre build the package
- final PackageBuilder builder = new PackageBuilder();
- builder.addPackage( packageDescr );
- final Package pkg = builder.getPackage();
-
- // add the package to a rulebase
- final RuleBase ruleBase = getRuleBase();
- ruleBase.addPackage( pkg );
- // load up the rulebase
- return ruleBase;
- }
-
- public void testDateEffective() throws Exception {
- // read in the source
- final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_EffectiveDate.drl" ) );
- final RuleBase ruleBase = loadRuleBase( reader );
-
- final WorkingMemory workingMemory = ruleBase.newStatefulSession();
-
- final List list = new ArrayList();
- workingMemory.setGlobal( "list",
- list );
-
- // go !
- final Message message = new Message( "hola" );
- workingMemory.insert( message );
- workingMemory.fireAllRules();
- assertFalse( message.isFired() );
-
- }
-}
+package org.drools.integrationtests;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.drools.Cheese;
+import org.drools.FactHandle;
+import org.drools.Person;
+import org.drools.PersonInterface;
+import org.drools.RuleBase;
+import org.drools.RuleBaseConfiguration;
+import org.drools.RuleBaseFactory;
+import org.drools.WorkingMemory;
+import org.drools.common.DefaultAgenda;
+import org.drools.common.InternalWorkingMemoryActions;
+import org.drools.common.RuleFlowGroupImpl;
+import org.drools.compiler.DrlParser;
+import org.drools.compiler.DroolsParserException;
+import org.drools.compiler.PackageBuilder;
+import org.drools.compiler.ProcessBuilder;
+import org.drools.compiler.PackageBuilder.PackageMergeException;
+import org.drools.event.ActivationCancelledEvent;
+import org.drools.event.ActivationCreatedEvent;
+import org.drools.event.AgendaEventListener;
+import org.drools.event.DefaultAgendaEventListener;
+import org.drools.Message;
+import org.drools.lang.descr.PackageDescr;
+import org.drools.rule.Package;
+import org.drools.ruleflow.common.instance.ProcessInstance;
+import org.drools.spi.Activation;
+import org.drools.spi.ActivationGroup;
+import org.drools.spi.AgendaGroup;
+
+public class ExecutionFlowControlTest extends TestCase {
+ protected RuleBase getRuleBase() throws Exception {
+
+ return RuleBaseFactory.newRuleBase( RuleBase.RETEOO,
+ null );
+ }
+
+ protected RuleBase getRuleBase(final RuleBaseConfiguration config) throws Exception {
+
+ return RuleBaseFactory.newRuleBase( RuleBase.RETEOO,
+ config );
+ }
+
+ public void testSalienceInteger() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_salienceIntegerRule.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ final PersonInterface person = new Person( "Edson",
+ "cheese" );
+ workingMemory.insert( person );
+
+ workingMemory.fireAllRules();
+
+ Assert.assertEquals( "Two rules should have been fired",
+ 2,
+ list.size() );
+ Assert.assertEquals( "Rule 3 should have been fired first",
+ "Rule 3",
+ list.get( 0 ) );
+ Assert.assertEquals( "Rule 2 should have been fired second",
+ "Rule 2",
+ list.get( 1 ) );
+ }
+
+ public void testSalienceExpression() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_salienceExpressionRule.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ final PersonInterface person10 = new Person( "bob",
+ "cheese",
+ 10);
+ workingMemory.insert( person10 );
+
+ final PersonInterface person20 = new Person( "mic",
+ "cheese",
+ 20);
+ workingMemory.insert( person20 );
+
+ workingMemory.fireAllRules();
+
+ Assert.assertEquals( "Two rules should have been fired",
+ 2,
+ list.size() );
+ Assert.assertEquals( "Rule 3 should have been fired first",
+ "Rule 3",
+ list.get( 0 ) );
+ Assert.assertEquals( "Rule 2 should have been fired second",
+ "Rule 2",
+ list.get( 1 ) );
+ }
+
+ public void testNoLoop() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "no-loop.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ final Cheese brie = new Cheese( "brie",
+ 12 );
+ workingMemory.insert( brie );
+
+ workingMemory.fireAllRules();
+
+ Assert.assertEquals( "Should not loop and thus size should be 1",
+ 1,
+ list.size() );
+
+ }
+
+ public void testLockOnActive() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LockOnActive.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ // AgendaGroup "group1" is not active, so should receive activation
+ final Cheese brie12 = new Cheese( "brie",
+ 12 );
+ workingMemory.insert( brie12 );
+ final AgendaGroup group1 = workingMemory.getAgenda().getAgendaGroup( "group1" );
+ assertEquals( 1,
+ group1.size() );
+
+ workingMemory.setFocus( "group1" );
+ // AgendaqGroup "group1" is now active, so should not receive activations
+ final Cheese brie10 = new Cheese( "brie",
+ 10 );
+ workingMemory.insert( brie10 );
+ assertEquals( 1,
+ group1.size() );
+
+ final Cheese cheddar20 = new Cheese( "cheddar",
+ 20 );
+ workingMemory.insert( cheddar20 );
+ final AgendaGroup group2 = workingMemory.getAgenda().getAgendaGroup( "group1" );
+ assertEquals( 1,
+ group2.size() );
+
+ final RuleFlowGroupImpl rfg = (RuleFlowGroupImpl) workingMemory.getAgenda().getRuleFlowGroup( "ruleflow2" );
+ rfg.setActive( true );
+ final Cheese cheddar17 = new Cheese( "cheddar",
+ 17 );
+ workingMemory.insert( cheddar17 );
+ assertEquals( 1,
+ group2.size() );
+ }
+
+ public void testLockOnActiveWithModify() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LockOnActiveWithUpdate.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ final WorkingMemory wm = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ wm.setGlobal( "list",
+ list );
+
+ final Cheese brie = new Cheese( "brie",
+ 13 );
+
+ final Person bob = new Person( "bob" );
+ bob.setCheese( brie );
+
+ final Person mic = new Person( "mic" );
+ mic.setCheese( brie );
+
+ final Person mark = new Person( "mark" );
+ mark.setCheese( brie );
+
+ final FactHandle brieHandle = wm.insert( brie );
+ wm.insert( bob );
+ wm.insert( mic );
+ wm.insert( mark );
+
+ final DefaultAgenda agenda = (DefaultAgenda) wm.getAgenda();
+ final AgendaGroup group1 = agenda.getAgendaGroup( "group1" );
+ agenda.setFocus( group1 );
+ assertEquals( 3,
+ group1.size() );
+ agenda.fireNextItem( null );
+ assertEquals( 2,
+ group1.size() );
+ wm.update( brieHandle,
+ brie );
+ assertEquals( 2,
+ group1.size() );
+
+ AgendaGroup group2 = agenda.getAgendaGroup( "group2" );
+ agenda.setFocus( group2 );
+
+ RuleFlowGroupImpl rfg = (RuleFlowGroupImpl) wm.getAgenda().getRuleFlowGroup( "ruleflow2" );
+ assertEquals( 3,
+ rfg.size() );
+
+ agenda.activateRuleFlowGroup( "ruleflow2" );
+ agenda.fireNextItem( null );
+ assertEquals( 2,
+ rfg.size() );
+ wm.update( brieHandle,
+ brie );
+ assertEquals( 2,
+ group2.size() );
+ }
+
+ public void testAgendaGroups() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_AgendaGroups.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ final Cheese brie = new Cheese( "brie",
+ 12 );
+ workingMemory.insert( brie );
+
+ workingMemory.fireAllRules();
+
+ assertEquals( 7,
+ list.size() );
+
+ assertEquals( "group3",
+ list.get( 0 ) );
+ assertEquals( "group4",
+ list.get( 1 ) );
+ assertEquals( "group3",
+ list.get( 2 ) );
+ assertEquals( "MAIN",
+ list.get( 3 ) );
+ assertEquals( "group1",
+ list.get( 4 ) );
+ assertEquals( "group1",
+ list.get( 5 ) );
+ assertEquals( "MAIN",
+ list.get( 6 ) );
+
+ workingMemory.setFocus( "group2" );
+ workingMemory.fireAllRules();
+
+ assertEquals( 8,
+ list.size() );
+ assertEquals( "group2",
+ list.get( 7 ) );
+ }
+
+ public void testActivationGroups() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_ActivationGroups.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ final Cheese brie = new Cheese( "brie",
+ 12 );
+ workingMemory.insert( brie );
+
+ final ActivationGroup activationGroup0 = workingMemory.getAgenda().getActivationGroup( "activation-group-0" );
+ assertEquals( 2,
+ activationGroup0.size() );
+
+ final ActivationGroup activationGroup3 = workingMemory.getAgenda().getActivationGroup( "activation-group-3" );
+ assertEquals( 1,
+ activationGroup3.size() );
+
+ final AgendaGroup agendaGroup3 = workingMemory.getAgenda().getAgendaGroup( "agenda-group-3" );
+ assertEquals( 1,
+ agendaGroup3.size() );
+
+ final AgendaGroup agendaGroupMain = workingMemory.getAgenda().getAgendaGroup( "MAIN" );
+ assertEquals( 3,
+ agendaGroupMain.size() );
+
+ workingMemory.clearAgendaGroup( "agenda-group-3" );
+ assertEquals( 0,
+ activationGroup3.size() );
+ assertEquals( 0,
+ agendaGroup3.size() );
+
+ workingMemory.fireAllRules();
+
+ assertEquals( 0,
+ activationGroup0.size() );
+
+ assertEquals( 2,
+ list.size() );
+ assertEquals( "rule0",
+ list.get( 0 ) );
+ assertEquals( "rule2",
+ list.get( 1 ) );
+
+ }
+
+ public void testDuration() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Duration.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ final Cheese brie = new Cheese( "brie",
+ 12 );
+ final FactHandle brieHandle = workingMemory.insert( brie );
+
+ workingMemory.fireAllRules();
+
+ // now check for update
+ assertEquals( 0,
+ list.size() );
+
+ // sleep for 300ms
+ Thread.sleep( 300 );
+
+ // now check for update
+ assertEquals( 1,
+ list.size() );
+
+ }
+
+ public void testInsertRetractNoloop() throws Exception {
+ // read in the source
+ final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_Insert_Retract_Noloop.drl" ) );
+ final RuleBase ruleBase = loadRuleBase( reader );
+
+ final WorkingMemory wm = ruleBase.newStatefulSession();
+ wm.insert( new Cheese( "stilton",
+ 15 ) );
+
+ wm.fireAllRules();
+ }
+
+ public void testDurationWithNoLoop() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Duration_with_NoLoop.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ final Cheese brie = new Cheese( "brie",
+ 12 );
+ final FactHandle brieHandle = workingMemory.insert( brie );
+
+ workingMemory.fireAllRules();
+
+ // now check for update
+ assertEquals( 0,
+ list.size() );
+
+ // sleep for 300ms
+ Thread.sleep( 300 );
+
+ // now check for update
+ assertEquals( 1,
+ list.size() );
+ }
+
+ public void testFireRuleAfterDuration() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_FireRuleAfterDuration.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ final Cheese brie = new Cheese( "brie",
+ 12 );
+ final FactHandle brieHandle = workingMemory.insert( brie );
+
+ workingMemory.fireAllRules();
+
+ // now check for update
+ assertEquals( 0,
+ list.size() );
+
+ // sleep for 300ms
+ Thread.sleep( 300 );
+
+ workingMemory.fireAllRules();
+
+ // now check for update
+ assertEquals( 2,
+ list.size() );
+
+ }
+
+ public void testUpdateNoLoop() throws Exception {
+ // JBRULES-780, throws a NullPointer or infinite loop if there is an issue
+ final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_UpdateNoloop.drl" ) );
+ final RuleBase ruleBase = loadRuleBase( reader );
+
+ final WorkingMemory wm = ruleBase.newStatefulSession();
+ wm.insert( new Cheese( "stilton",
+ 15 ) );
+
+ wm.fireAllRules();
+ }
+
+ public void testUpdateActivationCreationNoLoop() throws Exception {
+ // JBRULES-787, no-loop blocks all dependant tuples for update
+ final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_UpdateActivationCreationNoLoop.drl" ) );
+ final RuleBase ruleBase = loadRuleBase( reader );
+
+ final InternalWorkingMemoryActions wm = (InternalWorkingMemoryActions) ruleBase.newStatefulSession();
+ final List created = new ArrayList();
+ final List cancelled = new ArrayList();
+ final AgendaEventListener l = new DefaultAgendaEventListener() {
+ public void activationCreated(ActivationCreatedEvent event,
+ WorkingMemory workingMemory) {
+ created.add( event );
+ }
+
+ public void activationCancelled(ActivationCancelledEvent event,
+ WorkingMemory workingMemory) {
+ cancelled.add( event );
+ }
+
+ };
+
+ wm.addEventListener( l );
+
+ final Cheese stilton = new Cheese( "stilton",
+ 15 );
+ final FactHandle stiltonHandle = wm.insert( stilton );
+
+ final Person p1 = new Person( "p1" );
+ p1.setCheese( stilton );
+ wm.insert( p1 );
+
+ final Person p2 = new Person( "p2" );
+ p2.setCheese( stilton );
+ wm.insert( p2 );
+
+ final Person p3 = new Person( "p3" );
+ p3.setCheese( stilton );
+ wm.insert( p3 );
+
+ assertEquals( 3,
+ created.size() );
+ assertEquals( 0,
+ cancelled.size() );
+
+ final Activation item = ((ActivationCreatedEvent) created.get( 2 )).getActivation();
+
+ // simulate a modify inside a consequence
+ wm.update( stiltonHandle,
+ stilton,
+ item.getRule(),
+ item );
+
+ // the two of the three tuples should re-activate
+ assertEquals( 5,
+ created.size() );
+ assertEquals( 3,
+ cancelled.size() );
+ }
+
+ public void testRuleFlowGroup() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflowgroup.drl" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ workingMemory.insert( "Test" );
+ workingMemory.fireAllRules();
+ assertEquals( 0,
+ list.size() );
+
+ workingMemory.getAgenda().activateRuleFlowGroup( "Group1" );
+ workingMemory.fireAllRules();
+
+ assertEquals( 1,
+ list.size() );
+ }
+
+ public void testRuleFlow() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.drl" ) ) );
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );
+ final Package pkg = builder.getPackage();
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ workingMemory.fireAllRules();
+ assertEquals( 0,
+ list.size() );
+
+ final ProcessInstance processInstance = workingMemory.startProcess( "0" );
+ assertEquals( ProcessInstance.STATE_ACTIVE,
+ processInstance.getState() );
+ workingMemory.fireAllRules();
+ assertEquals( 4,
+ list.size() );
+ assertEquals( "Rule1",
+ list.get( 0 ) );
+ assertEquals( "Rule3",
+ list.get( 1 ) );
+ assertEquals( "Rule2",
+ list.get( 2 ) );
+ assertEquals( "Rule4",
+ list.get( 3 ) );
+ assertEquals( ProcessInstance.STATE_COMPLETED,
+ processInstance.getState() );
+ }
+
+ public void testRuleFlowClear() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_ruleflowClear.drl" ) ) );
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "test_ruleflowClear.rfm" ) ) );
+ final Package pkg = builder.getPackage();
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ final List activations = new ArrayList();
+ AgendaEventListener listener = new DefaultAgendaEventListener() {
+ public void activationCancelled(ActivationCancelledEvent event,
+ WorkingMemory workingMemory) {
+ activations.add( event.getActivation() );
+ }
+ };
+
+ workingMemory.addEventListener( listener );
+
+ assertEquals( 0 , workingMemory.getAgenda().getRuleFlowGroup( "flowgroup-1" ).size() );
+
+ // We need to call fireAllRules here to get the InitialFact into the system, to the eval(true)'s kick in
+ workingMemory.fireAllRules();
+
+ // Now we have 4 in the RuleFlow, but not yet in the agenda
+ assertEquals( 4 , workingMemory.getAgenda().getRuleFlowGroup( "flowgroup-1" ).size() );
+
+ // Check they aren't in the Agenda
+ assertEquals( 0, workingMemory.getAgenda().getAgendaGroup( "MAIN" ).size() );
+
+ // Start the process, which shoudl populate the Agenda
+ final ProcessInstance processInstance = workingMemory.startProcess( "ruleFlowClear" );
+ assertEquals( 4, workingMemory.getAgenda().getAgendaGroup( "MAIN" ).size() );
+
+
+ // Check we have 0 activation cancellation events
+ assertEquals( 0, activations.size() );
+
+ workingMemory.getAgenda().clearRuleFlowGroup( "flowgroup-1" );
+
+ // Check the AgendaGroup and RuleFlowGroup are now empty
+ assertEquals( 0, workingMemory.getAgenda().getAgendaGroup( "MAIN" ).size() );
+ assertEquals( 0 , workingMemory.getAgenda().getRuleFlowGroup( "flowgroup-1" ).size() );
+
+ // Check we have four activation cancellation events
+ assertEquals( 4, activations.size() );
+ }
+
+ public void testRuleFlowInPackage() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.drl" ) ) );
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );
+ final Package pkg = builder.getPackage();
+
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ workingMemory.fireAllRules();
+ assertEquals( 0,
+ list.size() );
+
+ final ProcessInstance processInstance = workingMemory.startProcess( "0" );
+ assertEquals( ProcessInstance.STATE_ACTIVE,
+ processInstance.getState() );
+ workingMemory.fireAllRules();
+ assertEquals( 4,
+ list.size() );
+ assertEquals( "Rule1",
+ list.get( 0 ) );
+ assertEquals( "Rule3",
+ list.get( 1 ) );
+ assertEquals( "Rule2",
+ list.get( 2 ) );
+ assertEquals( "Rule4",
+ list.get( 3 ) );
+ assertEquals( ProcessInstance.STATE_COMPLETED,
+ processInstance.getState() );
+
+ }
+
+ public void testLoadingRuleFlowInPackage1() throws Exception {
+ // adding ruleflow before adding package
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.drl" ) ) );
+ builder.getPackage();
+ }
+
+ public void testLoadingRuleFlowInPackage2() throws Exception {
+ // only adding ruleflow
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );
+ builder.getPackage();
+ }
+
+ public void testLoadingRuleFlowInPackage3() throws Exception {
+ // only adding ruleflow without any generated rules
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "empty_ruleflow.rfm" ) ) );
+ builder.getPackage();
+ }
+
+ public void testLoadingRuleFlowInPackage4() throws Exception {
+ // adding ruleflows of different package
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "empty_ruleflow.rfm" ) ) );
+ try {
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );
+ throw new Exception("An exception should have been thrown.");
+ } catch (PackageMergeException e) {
+ // do nothing
+ }
+ }
+
+ public void testLoadingRuleFlowInPackage5() throws Exception {
+ // adding ruleflow of different package than rules
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.drl" ) ) );
+ try {
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "empty_ruleflow.rfm" ) ) );
+ throw new Exception("An exception should have been thrown.");
+ } catch (PackageMergeException e) {
+ // do nothing
+ }
+ }
+
+ public void testLoadingRuleFlowInPackage6() throws Exception {
+ // adding rules of different package than ruleflow
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "empty_ruleflow.rfm" ) ) );
+ try {
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.drl" ) ) );
+ throw new Exception("An exception should have been thrown.");
+ } catch (PackageMergeException e) {
+ // do nothing
+ }
+ }
+
+ public void testLoadingRuleFlowInPackage7() throws Exception {
+ // loading a ruleflow with errors
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "error_ruleflow.rfm" ) ) );
+ assertEquals(1, builder.getErrors().getErrors().length);
+ }
+
+ private RuleBase loadRuleBase(final Reader reader) throws IOException,
+ DroolsParserException,
+ Exception {
+ final DrlParser parser = new DrlParser();
+ final PackageDescr packageDescr = parser.parse( reader );
+ if ( parser.hasErrors() ) {
+ Assert.fail( "Error messages in parser, need to sort this our (or else collect error messages)" );
+ }
+ // pre build the package
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackage( packageDescr );
+ final Package pkg = builder.getPackage();
+
+ // add the package to a rulebase
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+ // load up the rulebase
+ return ruleBase;
+ }
+
+ public void testDateEffective() throws Exception {
+ // read in the source
+ final Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_EffectiveDate.drl" ) );
+ final RuleBase ruleBase = loadRuleBase( reader );
+
+ final WorkingMemory workingMemory = ruleBase.newStatefulSession();
+
+ final List list = new ArrayList();
+ workingMemory.setGlobal( "list",
+ list );
+
+ // go !
+ final Message message = new Message( "hola" );
+ workingMemory.insert( message );
+ workingMemory.fireAllRules();
+ assertFalse( message.isFired() );
+
+ }
+}
Modified: labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java
===================================================================
--- labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java 2007-10-11 18:45:10 UTC (rev 15774)
+++ labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java 2007-10-11 18:49:52 UTC (rev 15775)
@@ -39,6 +39,7 @@
import org.acme.insurance.Driver;
import org.acme.insurance.Policy;
import org.drools.Address;
+import org.drools.Attribute;
import org.drools.Cell;
import org.drools.Cheese;
import org.drools.Cheesery;
@@ -96,7 +97,7 @@
import org.drools.event.WorkingMemoryEventListener;
import org.drools.facttemplates.Fact;
import org.drools.facttemplates.FactTemplate;
-import org.drools.integrationtests.helloworld.Message;
+import org.drools.Message;
import org.drools.lang.DrlDumper;
import org.drools.lang.descr.AttributeDescr;
import org.drools.lang.descr.PackageDescr;
@@ -110,6 +111,7 @@
import org.drools.spi.GlobalResolver;
import org.drools.xml.XmlDumper;
+
/** Run all the tests with the ReteOO engine implementation */
public class MiscTest extends TestCase {
@@ -397,7 +399,29 @@
list.size() );
}
+
+ public void NullFieldOnCompositeSink() throws Exception {
+ final PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_NullFieldOnCompositeSink.drl" ) ) );
+ final Package pkg = builder.getPackage();
+ // add the package to a rulebase
+ final RuleBase ruleBase = getRuleBase();
+ ruleBase.addPackage( pkg );
+
+ WorkingMemory workingMemory = ruleBase.newStatefulSession();
+ List list = new ArrayList();
+ workingMemory.setGlobal("list", list);
+
+ workingMemory.insert(new Attribute());
+ workingMemory.insert(new Message());
+ workingMemory.fireAllRules();
+
+ assertEquals(1, list.size());
+ assertEquals("X", list.get(0));
+
+ }
+
public void testEmptyPattern() throws Exception {
// pre build the package
final PackageBuilder builder = new PackageBuilder();
Modified: labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/HelloWorld.drl
===================================================================
--- labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/HelloWorld.drl 2007-10-11 18:45:10 UTC (rev 15774)
+++ labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/HelloWorld.drl 2007-10-11 18:49:52 UTC (rev 15775)
@@ -7,7 +7,7 @@
rule "Hello World"
when
- $m : org.drools.integrationtests.helloworld.Message(list contains "hello",
+ $m : org.drools.Message(list contains "hello",
text:message == "hola",
number > 40,
birthday > "10-Jul-1974",
Modified: labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/test_EffectiveDate.drl
===================================================================
--- labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/test_EffectiveDate.drl 2007-10-11 18:45:10 UTC (rev 15774)
+++ labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/test_EffectiveDate.drl 2007-10-11 18:49:52 UTC (rev 15775)
@@ -9,7 +9,7 @@
date-effective "9-Jul-1974"
date-expires "10-Jul-1974"
when
- $m : org.drools.integrationtests.helloworld.Message()
+ $m : org.drools.Message()
then
$m.setFired(true);
end
Modified: labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/test_ExplicitAnd.drl
===================================================================
--- labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/test_ExplicitAnd.drl 2007-10-11 18:45:10 UTC (rev 15774)
+++ labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-compiler/src/test/resources/org/drools/integrationtests/test_ExplicitAnd.drl 2007-10-11 18:49:52 UTC (rev 15775)
@@ -1,6 +1,6 @@
package HelloWorld
-import org.drools.integrationtests.helloworld.Message
+import org.drools.Message
import org.drools.Cheese;
global java.util.List list;
Modified: labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-core/src/main/java/org/drools/reteoo/CompositeObjectSinkAdapter.java
===================================================================
--- labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-core/src/main/java/org/drools/reteoo/CompositeObjectSinkAdapter.java 2007-10-11 18:45:10 UTC (rev 15774)
+++ labs/jbossrules/branches/Branch_4_0_2_SOA_4_2/drools-core/src/main/java/org/drools/reteoo/CompositeObjectSinkAdapter.java 2007-10-11 18:49:52 UTC (rev 15775)
@@ -1,690 +1,734 @@
-package org.drools.reteoo;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.drools.base.ValueType;
-import org.drools.base.evaluators.Operator;
-import org.drools.common.InternalFactHandle;
-import org.drools.common.InternalWorkingMemory;
-import org.drools.rule.LiteralConstraint;
-import org.drools.spi.AlphaNodeFieldConstraint;
-import org.drools.spi.Evaluator;
-import org.drools.spi.Extractor;
-import org.drools.spi.FieldExtractor;
-import org.drools.spi.FieldValue;
-import org.drools.spi.PropagationContext;
-import org.drools.util.Iterator;
-import org.drools.util.LinkedList;
-import org.drools.util.LinkedListNode;
-import org.drools.util.ObjectHashMap;
-import org.drools.util.ObjectHashMap.ObjectEntry;
-
-public class CompositeObjectSinkAdapter
- implements
- ObjectSinkPropagator {
-
- // /** You can override this property via a system property (eg -Ddrools.hashThreshold=4) */
- // public static final String HASH_THRESHOLD_SYSTEM_PROPERTY = "drools.hashThreshold";
- //
- // /** The threshold for when hashing kicks in */
- // public static final int THRESHOLD_TO_HASH = Integer.parseInt( System.getProperty( HASH_THRESHOLD_SYSTEM_PROPERTY,
- // "3" ) );
-
- private static final long serialVersionUID = 400L;
- ObjectSinkNodeList otherSinks;
- ObjectSinkNodeList hashableSinks;
-
- LinkedList hashedFieldIndexes;
-
- ObjectHashMap hashedSinkMap;
-
- private HashKey hashKey;
-
- private final int alphaNodeHashingThreshold;
-
- public CompositeObjectSinkAdapter() {
- this( 3 );
- }
-
- public CompositeObjectSinkAdapter(final int alphaNodeHashingThreshold) {
- this.hashKey = new HashKey();
- this.alphaNodeHashingThreshold = alphaNodeHashingThreshold;
- }
-
- public void addObjectSink(final ObjectSink sink) {
- if ( sink instanceof AlphaNode ) {
- final AlphaNode alphaNode = (AlphaNode) sink;
- final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
-
- if ( fieldConstraint instanceof LiteralConstraint ) {
- final LiteralConstraint literalConstraint = (LiteralConstraint) fieldConstraint;
- final Evaluator evaluator = literalConstraint.getEvaluator();
-
- if ( evaluator.getOperator() == Operator.EQUAL ) {
- final int index = literalConstraint.getFieldExtractor().getIndex();
- final FieldIndex fieldIndex = registerFieldIndex( index,
- literalConstraint.getFieldExtractor() );
-
- if ( fieldIndex.getCount() >= this.alphaNodeHashingThreshold ) {
- if ( !fieldIndex.isHashed() ) {
- hashSinks( fieldIndex );
- }
- final FieldValue value = literalConstraint.getField();
- // no need to check, we know the sink does not exist
- this.hashedSinkMap.put( new HashKey( index,
- value ),
- sink,
- false );
- } else {
- if ( this.hashableSinks == null ) {
- this.hashableSinks = new ObjectSinkNodeList();
- }
- this.hashableSinks.add( (ObjectSinkNode) sink );
- }
- return;
- }
-
- }
- }
-
- if ( this.otherSinks == null ) {
- this.otherSinks = new ObjectSinkNodeList();
- }
-
- this.otherSinks.add( (ObjectSinkNode) sink );
- }
-
- public void removeObjectSink(final ObjectSink sink) {
- if ( sink instanceof AlphaNode ) {
- final AlphaNode alphaNode = (AlphaNode) sink;
- final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
-
- if ( fieldConstraint instanceof LiteralConstraint ) {
- final LiteralConstraint literalConstraint = (LiteralConstraint) fieldConstraint;
- final Evaluator evaluator = literalConstraint.getEvaluator();
- final FieldValue value = literalConstraint.getField();
-
- if ( evaluator.getOperator() == Operator.EQUAL ) {
- final int index = literalConstraint.getFieldExtractor().getIndex();
- final FieldIndex fieldIndex = unregisterFieldIndex( index );
-
- if ( fieldIndex.isHashed() ) {
- this.hashKey.setValue( index,
- value );
- this.hashedSinkMap.remove( this.hashKey );
- if ( fieldIndex.getCount() <= this.alphaNodeHashingThreshold - 1 ) {
- // we have less than three so unhash
- unHashSinks( fieldIndex );
- }
- } else {
- this.hashableSinks.remove( (ObjectSinkNode) sink );
- }
-
- if ( this.hashableSinks != null && this.hashableSinks.isEmpty() ) {
- this.hashableSinks = null;
- }
-
- return;
- }
- }
- }
-
- this.otherSinks.remove( (ObjectSinkNode) sink );
-
- if ( this.otherSinks.isEmpty() ) {
- this.otherSinks = null;
- }
- }
-
- public void hashSinks(final FieldIndex fieldIndex) {
- final int index = fieldIndex.getIndex();
-
- final List list = new ArrayList();
-
- if ( this.hashedSinkMap == null ) {
- this.hashedSinkMap = new ObjectHashMap();
- }
-
- for ( ObjectSinkNode sink = this.hashableSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
- final AlphaNode alphaNode = (AlphaNode) sink;
- final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
- final LiteralConstraint literalConstraint = (LiteralConstraint) fieldConstraint;
- final Evaluator evaluator = literalConstraint.getEvaluator();
- if ( evaluator.getOperator() == Operator.EQUAL && index == literalConstraint.getFieldExtractor().getIndex() ) {
- final FieldValue value = literalConstraint.getField();
- list.add( sink );
- this.hashedSinkMap.put( new HashKey( index,
- value ),
- sink );
- }
- }
-
- for ( final java.util.Iterator it = list.iterator(); it.hasNext(); ) {
- final ObjectSinkNode sink = (ObjectSinkNode) it.next();
- this.hashableSinks.remove( sink );
- }
-
- if ( this.hashableSinks.isEmpty() ) {
- this.hashableSinks = null;
- }
-
- fieldIndex.setHashed( true );
- }
-
- public void unHashSinks(final FieldIndex fieldIndex) {
- final int index = fieldIndex.getIndex();
-
- final List sinks = new ArrayList();
-
- //iterate twice as custom iterator is immutable
- final Iterator mapIt = this.hashedSinkMap.newIterator();
- for ( ObjectHashMap.ObjectEntry e = (ObjectHashMap.ObjectEntry) mapIt.next(); e != null; ) {
-
- sinks.add( e.getValue() );
- e = (ObjectHashMap.ObjectEntry) mapIt.next();
- }
-
- for ( final java.util.Iterator iter = sinks.iterator(); iter.hasNext(); ) {
- final AlphaNode sink = (AlphaNode) iter.next();
- final AlphaNode alphaNode = sink;
- final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
- final LiteralConstraint literalConstraint = (LiteralConstraint) fieldConstraint;
- final Evaluator evaluator = literalConstraint.getEvaluator();
- if ( evaluator.getOperator() == Operator.EQUAL && index == literalConstraint.getFieldExtractor().getIndex() ) {
- final FieldValue value = literalConstraint.getField();
- if ( this.hashableSinks == null ) {
- this.hashableSinks = new ObjectSinkNodeList();
- }
- this.hashableSinks.add( sink );
- this.hashedSinkMap.remove( new HashKey( index,
- value ) );
- };
- }
-
- if ( this.hashedSinkMap.isEmpty() ) {
- this.hashedSinkMap = null;
- }
-
- fieldIndex.setHashed( false );
- }
-
- /**
- * Returns a FieldIndex which Keeps a count on how many times a particular field is used with an equality check in the sinks.
- * @param index
- * @param fieldExtractor
- * @return
- */
- private FieldIndex registerFieldIndex(final int index,
- final FieldExtractor fieldExtractor) {
- FieldIndex fieldIndex = null;
-
- // is linkedlist null, if so create and add
- if ( this.hashedFieldIndexes == null ) {
- this.hashedFieldIndexes = new LinkedList();
- fieldIndex = new FieldIndex( index,
- fieldExtractor );
- this.hashedFieldIndexes.add( fieldIndex );
- }
-
- // still null, so see if it already exists
- if ( fieldIndex == null ) {
- fieldIndex = findFieldIndex( index );
- }
-
- // doesn't exist so create it
- if ( fieldIndex == null ) {
- fieldIndex = new FieldIndex( index,
- fieldExtractor );
- this.hashedFieldIndexes.add( fieldIndex );
- }
-
- fieldIndex.increaseCounter();
-
- return fieldIndex;
- }
-
- private FieldIndex unregisterFieldIndex(final int index) {
- final FieldIndex fieldIndex = findFieldIndex( index );
- fieldIndex.decreaseCounter();
-
- // if the fieldcount is 0 then remove it from the linkedlist
- if ( fieldIndex.getCount() == 0 ) {
- this.hashedFieldIndexes.remove( fieldIndex );
-
- // if the linkedlist is empty then null it
- if ( this.hashedFieldIndexes.isEmpty() ) {
- this.hashedFieldIndexes = null;
- }
- }
-
- return fieldIndex;
- }
-
- private FieldIndex findFieldIndex(final int index) {
- for ( FieldIndex node = (FieldIndex) this.hashedFieldIndexes.getFirst(); node != null; node = (FieldIndex) node.getNext() ) {
- if ( node.getIndex() == index ) {
- return node;
- }
- }
-
- return null;
- }
-
- public void propagateAssertObject(final InternalFactHandle handle,
- final PropagationContext context,
- final InternalWorkingMemory workingMemory) {
- final Object object = handle.getObject();
-
- // Iterates t he FieldIndex collection, which tells you if particularly field is hashed or not
- // if the field is hashed then it builds the hashkey to return the correct sink for the current objects slot's
- // value, one object may have multiple fields indexed.
- if ( this.hashedFieldIndexes != null ) {
- // Iterate the FieldIndexes to see if any are hashed
- for ( FieldIndex fieldIndex = (FieldIndex) this.hashedFieldIndexes.getFirst(); fieldIndex != null; fieldIndex = (FieldIndex) fieldIndex.getNext() ) {
- if ( !fieldIndex.isHashed() ) {
- continue;
- }
- // this field is hashed so set the existing hashKey and see if there is a sink for it
- final int index = fieldIndex.getIndex();
- final FieldExtractor extractor = fieldIndex.getFieldExtactor();
- this.hashKey.setValue( index,
- object,
- extractor );
- final ObjectSink sink = (ObjectSink) this.hashedSinkMap.get( this.hashKey );
- if ( sink != null ) {
- // The sink exists so propagate
- sink.assertObject( handle,
- context,
- workingMemory );
- }
- }
- }
-
- // propagate unhashed
- if ( this.hashableSinks != null ) {
- for ( ObjectSinkNode sink = this.hashableSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
- sink.assertObject( handle,
- context,
- workingMemory );
- }
- }
-
- if ( this.otherSinks != null ) {
- // propagate others
- for ( ObjectSinkNode sink = this.otherSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
- sink.assertObject( handle,
- context,
- workingMemory );
- }
- }
-
- }
-
- public void propagateRetractObject(final InternalFactHandle handle,
- final PropagationContext context,
- final InternalWorkingMemory workingMemory,
- final boolean useHash) {
- if ( this.hashedFieldIndexes != null ) {
- if ( useHash && this.hashedSinkMap != null ) {
- final Object object = handle.getObject();
- // Iterate the FieldIndexes to see if any are hashed
- for ( FieldIndex fieldIndex = (FieldIndex) this.hashedFieldIndexes.getFirst(); fieldIndex != null; fieldIndex = (FieldIndex) fieldIndex.getNext() ) {
- // this field is hashed so set the existing hashKey and see if there is a sink for it
- if ( !fieldIndex.isHashed() ) {
- continue;
- }
-
- final int index = fieldIndex.getIndex();
- final FieldExtractor extractor = fieldIndex.getFieldExtactor();
- this.hashKey.setValue( index,
- object,
- extractor );
- final ObjectSink sink = (ObjectSink) this.hashedSinkMap.get( this.hashKey );
- if ( sink != null ) {
- // The sink exists so propagate
- sink.retractObject( handle,
- context,
- workingMemory );
- }
- }
- } else if ( this.hashedSinkMap != null ) {
- final Iterator it = this.hashedSinkMap.newIterator();
- for ( ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next() ) {
- final ObjectSink sink = (ObjectSink) entry.getValue();
- sink.retractObject( handle,
- context,
- workingMemory );
- }
- }
- }
-
- if ( this.hashableSinks != null ) {
- // we can't retrieve hashed sinks, as the field value might have changed, so we have to iterate and propagate to all hashed sinks
- for ( ObjectSinkNode sink = this.hashableSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
- sink.retractObject( handle,
- context,
- workingMemory );
- }
- }
-
- if ( this.otherSinks != null ) {
- // propagate others
- for ( ObjectSinkNode sink = this.otherSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
- sink.retractObject( handle,
- context,
- workingMemory );
- }
- }
- }
-
- public ObjectSink[] getSinks() {
- final List list = new ArrayList();
-
- if ( this.otherSinks != null ) {
- for ( ObjectSinkNode sink = this.otherSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
- list.add( sink );
- }
- }
-
- if ( this.hashableSinks != null ) {
- for ( ObjectSinkNode sink = this.hashableSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
- list.add( sink );
- }
- }
-
- if ( this.hashedSinkMap != null ) {
- final Iterator it = this.hashedSinkMap.newIterator();
- for ( ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next() ) {
- final ObjectSink sink = (ObjectSink) entry.getValue();
- list.add( sink );
- }
- }
-
- return (ObjectSink[]) list.toArray( new ObjectSink[list.size()] );
- }
-
- public int size() {
- int size = 0;
- size += ((this.otherSinks != null) ? this.otherSinks.size() : 0);
- size += ((this.hashableSinks != null) ? this.hashableSinks.size() : 0);
- size += ((this.hashedSinkMap != null) ? this.hashedSinkMap.size() : 0);
- return size;
- }
-
- public static class HashKey
- implements
- Serializable {
- private static final long serialVersionUID = 400L;
-
- private static final byte OBJECT = 1;
- private static final byte LONG = 2;
- private static final byte DOUBLE = 3;
- private static final byte BOOL = 4;
-
- private int index;
-
- private byte type;
- private Object ovalue;
- private long lvalue;
- private boolean bvalue;
- private double dvalue;
-
- private int hashCode;
-
- public HashKey() {
- }
-
- public HashKey(final int index,
- final FieldValue value) {
- this.setValue( index,
- value );
- }
-
- public HashKey(final int index,
- final Object value,
- final Extractor extractor) {
- this.setValue( index,
- value,
- extractor );
- }
-
- public int getIndex() {
- return this.index;
- }
-
- public void setValue(final int index,
- final Object value,
- final Extractor extractor) {
- this.index = index;
- final ValueType vtype = extractor.getValueType();
- if ( vtype.isBoolean() ) {
- this.bvalue = extractor.getBooleanValue( null, value );
- this.type = BOOL;
- this.setHashCode( this.bvalue ? 1231 : 1237 );
- } else if ( vtype.isIntegerNumber() ) {
- this.lvalue = extractor.getLongValue( null, value );
- this.type = LONG;
- this.setHashCode( (int) (this.lvalue ^ (this.lvalue >>> 32)) );
- } else if ( vtype.isFloatNumber() ) {
- this.dvalue = extractor.getDoubleValue( null, value );
- this.type = DOUBLE;
- final long temp = Double.doubleToLongBits( this.dvalue );
- this.setHashCode( (int) (temp ^ (temp >>> 32)) );
- } else {
- this.ovalue = extractor.getValue( null, value );
- this.type = OBJECT;
- this.setHashCode( this.ovalue != null ? this.ovalue.hashCode() : 0 );
- }
- }
-
- public void setValue(final int index,
- final FieldValue value) {
- this.index = index;
- if ( value.isBooleanField() ) {
- this.bvalue = value.getBooleanValue();
- this.type = BOOL;
- this.setHashCode( this.bvalue ? 1231 : 1237 );
- } else if ( value.isIntegerNumberField() ) {
- this.lvalue = value.getLongValue();
- this.type = LONG;
- this.setHashCode( (int) (this.lvalue ^ (this.lvalue >>> 32)) );
- } else if ( value.isFloatNumberField() ) {
- this.dvalue = value.getDoubleValue();
- this.type = DOUBLE;
- final long temp = Double.doubleToLongBits( this.dvalue );
- this.setHashCode( (int) (temp ^ (temp >>> 32)) );
- } else {
- this.ovalue = value.getValue();
- this.type = OBJECT;
- this.setHashCode( this.ovalue != null ? this.ovalue.hashCode() : 0 );
- }
- }
-
- private void setHashCode(final int hashSeed) {
- final int PRIME = 31;
- int result = 1;
- result = PRIME * result + hashSeed;
- result = PRIME * result + this.index;
- this.hashCode = result;
- }
-
- public boolean getBooleanValue() {
- switch ( this.type ) {
- case BOOL :
- return this.bvalue;
- case OBJECT :
- if ( this.ovalue == null ) {
- return false;
- } else if ( this.ovalue instanceof Boolean ) {
- return ((Boolean) this.ovalue).booleanValue();
- } else if ( this.ovalue instanceof String ) {
- return Boolean.valueOf( (String) this.ovalue ).booleanValue();
- } else {
- throw new ClassCastException( "Can't convert " + this.ovalue.getClass() + " to a boolean value." );
- }
- case LONG :
- throw new ClassCastException( "Can't convert long to a boolean value." );
- case DOUBLE :
- throw new ClassCastException( "Can't convert double to a boolean value." );
-
- }
- return false;
- }
-
- public long getLongValue() {
- switch ( this.type ) {
- case BOOL :
- return this.bvalue ? 1 : 0;
- case OBJECT :
- if ( this.ovalue == null ) {
- return 0;
- } else if ( this.ovalue instanceof Number ) {
- return ((Number) this.ovalue).longValue();
- } else if ( this.ovalue instanceof String ) {
- return Long.parseLong( (String) this.ovalue );
- } else {
- throw new ClassCastException( "Can't convert " + this.ovalue.getClass() + " to a long value." );
- }
- case LONG :
- return this.lvalue;
- case DOUBLE :
- return (long) this.dvalue;
-
- }
- return 0;
- }
-
- public double getDoubleValue() {
- switch ( this.type ) {
- case BOOL :
- return this.bvalue ? 1 : 0;
- case OBJECT :
- if ( this.ovalue == null ) {
- return 0;
- } else if ( this.ovalue instanceof Number ) {
- return ((Number) this.ovalue).doubleValue();
- } else if ( this.ovalue instanceof String ) {
- return Double.parseDouble( (String) this.ovalue );
- } else {
- throw new ClassCastException( "Can't convert " + this.ovalue.getClass() + " to a double value." );
- }
- case LONG :
- return this.lvalue;
- case DOUBLE :
- return this.dvalue;
- }
- return 0;
- }
-
- public Object getObjectValue() {
- switch ( this.type ) {
- case BOOL :
- return this.bvalue ? Boolean.TRUE : Boolean.FALSE;
- case OBJECT :
- return this.ovalue;
- case LONG :
- return new Long( this.lvalue );
- case DOUBLE :
- return new Double( this.dvalue );
- }
- return null;
- }
-
- public int hashCode() {
- return this.hashCode;
- }
-
- public boolean equals(final Object object) {
- final HashKey other = (HashKey) object;
-
- switch ( this.type ) {
- case BOOL :
- return (this.index == other.index) && (this.bvalue == other.getBooleanValue());
- case LONG :
- return (this.index == other.index) && (this.lvalue == other.getLongValue());
- case DOUBLE :
- return (this.index == other.index) && (this.dvalue == other.getDoubleValue());
- case OBJECT :
- final Object otherValue = other.getObjectValue();
- if ( (this.ovalue != null) && (this.ovalue instanceof Number) && (otherValue instanceof Number) ) {
- return (this.index == other.index) && (((Number) this.ovalue).doubleValue() == ((Number) otherValue).doubleValue());
- }
- return (this.index == other.index) && ( this.ovalue == null ? otherValue == null : this.ovalue.equals( otherValue ));
- }
- return false;
- }
-
- }
-
- public static class FieldIndex
- implements
- LinkedListNode {
- private static final long serialVersionUID = 400L;
- private final int index;
- private FieldExtractor fieldExtactor;
-
- private int count;
-
- private boolean hashed;
-
- private LinkedListNode previous;
- private LinkedListNode next;
-
- public FieldIndex(final int index,
- final FieldExtractor fieldExtractor) {
- this.index = index;
- this.fieldExtactor = fieldExtractor;
- }
-
- public FieldExtractor getFieldExtractor() {
- return this.fieldExtactor;
- }
-
- public int getIndex() {
- return this.index;
- }
-
- public int getCount() {
- return this.count;
- }
-
- public FieldExtractor getFieldExtactor() {
- return this.fieldExtactor;
- }
-
- public boolean isHashed() {
- return this.hashed;
- }
-
- public void setHashed(final boolean hashed) {
- this.hashed = hashed;
- }
-
- public void increaseCounter() {
- this.count++;
- }
-
- public void decreaseCounter() {
- this.count--;
- }
-
- public LinkedListNode getNext() {
- return this.next;
- }
-
- public LinkedListNode getPrevious() {
- return this.previous;
- }
-
- public void setNext(final LinkedListNode next) {
- this.next = next;
-
- }
-
- public void setPrevious(final LinkedListNode previous) {
- this.previous = previous;
- }
- }
-}
+package org.drools.reteoo;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.drools.base.ValueType;
+import org.drools.base.evaluators.Operator;
+import org.drools.common.InternalFactHandle;
+import org.drools.common.InternalWorkingMemory;
+import org.drools.rule.LiteralConstraint;
+import org.drools.spi.AlphaNodeFieldConstraint;
+import org.drools.spi.Evaluator;
+import org.drools.spi.Extractor;
+import org.drools.spi.FieldExtractor;
+import org.drools.spi.FieldValue;
+import org.drools.spi.PropagationContext;
+import org.drools.util.Iterator;
+import org.drools.util.LinkedList;
+import org.drools.util.LinkedListNode;
+import org.drools.util.ObjectHashMap;
+import org.drools.util.ObjectHashMap.ObjectEntry;
+
+public class CompositeObjectSinkAdapter
+ implements
+ ObjectSinkPropagator {
+
+ // /** You can override this property via a system property (eg -Ddrools.hashThreshold=4) */
+ // public static final String HASH_THRESHOLD_SYSTEM_PROPERTY = "drools.hashThreshold";
+ //
+ // /** The threshold for when hashing kicks in */
+ // public static final int THRESHOLD_TO_HASH = Integer.parseInt( System.getProperty( HASH_THRESHOLD_SYSTEM_PROPERTY,
+ // "3" ) );
+
+ private static final long serialVersionUID = 400L;
+ ObjectSinkNodeList otherSinks;
+ ObjectSinkNodeList hashableSinks;
+
+ LinkedList hashedFieldIndexes;
+
+ ObjectHashMap hashedSinkMap;
+
+ private HashKey hashKey;
+
+ private final int alphaNodeHashingThreshold;
+
+ public CompositeObjectSinkAdapter() {
+ this( 3 );
+ }
+
+ public CompositeObjectSinkAdapter(final int alphaNodeHashingThreshold) {
+ this.hashKey = new HashKey();
+ this.alphaNodeHashingThreshold = alphaNodeHashingThreshold;
+ }
+
+ public void addObjectSink(final ObjectSink sink) {
+ if ( sink instanceof AlphaNode ) {
+ final AlphaNode alphaNode = (AlphaNode) sink;
+ final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
+
+ if ( fieldConstraint instanceof LiteralConstraint ) {
+ final LiteralConstraint literalConstraint = (LiteralConstraint) fieldConstraint;
+ final Evaluator evaluator = literalConstraint.getEvaluator();
+
+ if ( evaluator.getOperator() == Operator.EQUAL ) {
+ final int index = literalConstraint.getFieldExtractor().getIndex();
+ final FieldIndex fieldIndex = registerFieldIndex( index,
+ literalConstraint.getFieldExtractor() );
+
+ if ( fieldIndex.getCount() >= this.alphaNodeHashingThreshold && this.alphaNodeHashingThreshold != 0) {
+ if ( !fieldIndex.isHashed() ) {
+ hashSinks( fieldIndex );
+ }
+ final FieldValue value = literalConstraint.getField();
+ // no need to check, we know the sink does not exist
+ this.hashedSinkMap.put( new HashKey( index,
+ value ),
+ sink,
+ false );
+ } else {
+ if ( this.hashableSinks == null ) {
+ this.hashableSinks = new ObjectSinkNodeList();
+ }
+ this.hashableSinks.add( (ObjectSinkNode) sink );
+ }
+ return;
+ }
+
+ }
+ }
+
+ if ( this.otherSinks == null ) {
+ this.otherSinks = new ObjectSinkNodeList();
+ }
+
+ this.otherSinks.add( (ObjectSinkNode) sink );
+ }
+
+ public void removeObjectSink(final ObjectSink sink) {
+ if ( sink instanceof AlphaNode ) {
+ final AlphaNode alphaNode = (AlphaNode) sink;
+ final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
+
+ if ( fieldConstraint instanceof LiteralConstraint ) {
+ final LiteralConstraint literalConstraint = (LiteralConstraint) fieldConstraint;
+ final Evaluator evaluator = literalConstraint.getEvaluator();
+ final FieldValue value = literalConstraint.getField();
+
+ if ( evaluator.getOperator() == Operator.EQUAL ) {
+ final int index = literalConstraint.getFieldExtractor().getIndex();
+ final FieldIndex fieldIndex = unregisterFieldIndex( index );
+
+ if ( fieldIndex.isHashed() ) {
+ this.hashKey.setValue( index,
+ value );
+ this.hashedSinkMap.remove( this.hashKey );
+ if ( fieldIndex.getCount() <= this.alphaNodeHashingThreshold - 1 ) {
+ // we have less than three so unhash
+ unHashSinks( fieldIndex );
+ }
+ } else {
+ this.hashableSinks.remove( (ObjectSinkNode) sink );
+ }
+
+ if ( this.hashableSinks != null && this.hashableSinks.isEmpty() ) {
+ this.hashableSinks = null;
+ }
+
+ return;
+ }
+ }
+ }
+
+ this.otherSinks.remove( (ObjectSinkNode) sink );
+
+ if ( this.otherSinks.isEmpty() ) {
+ this.otherSinks = null;
+ }
+ }
+
+ public void hashSinks(final FieldIndex fieldIndex) {
+ final int index = fieldIndex.getIndex();
+
+ final List list = new ArrayList();
+
+ if ( this.hashedSinkMap == null ) {
+ this.hashedSinkMap = new ObjectHashMap();
+ }
+
+ for ( ObjectSinkNode sink = this.hashableSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
+ final AlphaNode alphaNode = (AlphaNode) sink;
+ final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
+ final LiteralConstraint literalConstraint = (LiteralConstraint) fieldConstraint;
+ final Evaluator evaluator = literalConstraint.getEvaluator();
+ if ( evaluator.getOperator() == Operator.EQUAL && index == literalConstraint.getFieldExtractor().getIndex() ) {
+ final FieldValue value = literalConstraint.getField();
+ list.add( sink );
+ this.hashedSinkMap.put( new HashKey( index,
+ value ),
+ sink );
+ }
+ }
+
+ for ( final java.util.Iterator it = list.iterator(); it.hasNext(); ) {
+ final ObjectSinkNode sink = (ObjectSinkNode) it.next();
+ this.hashableSinks.remove( sink );
+ }
+
+ if ( this.hashableSinks.isEmpty() ) {
+ this.hashableSinks = null;
+ }
+
+ fieldIndex.setHashed( true );
+ }
+
+ public void unHashSinks(final FieldIndex fieldIndex) {
+ final int index = fieldIndex.getIndex();
+
+ final List sinks = new ArrayList();
+
+ //iterate twice as custom iterator is immutable
+ final Iterator mapIt = this.hashedSinkMap.newIterator();
+ for ( ObjectHashMap.ObjectEntry e = (ObjectHashMap.ObjectEntry) mapIt.next(); e != null; ) {
+
+ sinks.add( e.getValue() );
+ e = (ObjectHashMap.ObjectEntry) mapIt.next();
+ }
+
+ for ( final java.util.Iterator iter = sinks.iterator(); iter.hasNext(); ) {
+ final AlphaNode sink = (AlphaNode) iter.next();
+ final AlphaNode alphaNode = sink;
+ final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
+ final LiteralConstraint literalConstraint = (LiteralConstraint) fieldConstraint;
+ final Evaluator evaluator = literalConstraint.getEvaluator();
+ if ( evaluator.getOperator() == Operator.EQUAL && index == literalConstraint.getFieldExtractor().getIndex() ) {
+ final FieldValue value = literalConstraint.getField();
+ if ( this.hashableSinks == null ) {
+ this.hashableSinks = new ObjectSinkNodeList();
+ }
+ this.hashableSinks.add( sink );
+ this.hashedSinkMap.remove( new HashKey( index,
+ value ) );
+ };
+ }
+
+ if ( this.hashedSinkMap.isEmpty() ) {
+ this.hashedSinkMap = null;
+ }
+
+ fieldIndex.setHashed( false );
+ }
+
+ /**
+ * Returns a FieldIndex which Keeps a count on how many times a particular field is used with an equality check in the sinks.
+ * @param index
+ * @param fieldExtractor
+ * @return
+ */
+ private FieldIndex registerFieldIndex(final int index,
+ final FieldExtractor fieldExtractor) {
+ FieldIndex fieldIndex = null;
+
+ // is linkedlist null, if so create and add
+ if ( this.hashedFieldIndexes == null ) {
+ this.hashedFieldIndexes = new LinkedList();
+ fieldIndex = new FieldIndex( index,
+ fieldExtractor );
+ this.hashedFieldIndexes.add( fieldIndex );
+ }
+
+ // still null, so see if it already exists
+ if ( fieldIndex == null ) {
+ fieldIndex = findFieldIndex( index );
+ }
+
+ // doesn't exist so create it
+ if ( fieldIndex == null ) {
+ fieldIndex = new FieldIndex( index,
+ fieldExtractor );
+ this.hashedFieldIndexes.add( fieldIndex );
+ }
+
+ fieldIndex.increaseCounter();
+
+ return fieldIndex;
+ }
+
+ private FieldIndex unregisterFieldIndex(final int index) {
+ final FieldIndex fieldIndex = findFieldIndex( index );
+ fieldIndex.decreaseCounter();
+
+ // if the fieldcount is 0 then remove it from the linkedlist
+ if ( fieldIndex.getCount() == 0 ) {
+ this.hashedFieldIndexes.remove( fieldIndex );
+
+ // if the linkedlist is empty then null it
+ if ( this.hashedFieldIndexes.isEmpty() ) {
+ this.hashedFieldIndexes = null;
+ }
+ }
+
+ return fieldIndex;
+ }
+
+ private FieldIndex findFieldIndex(final int index) {
+ for ( FieldIndex node = (FieldIndex) this.hashedFieldIndexes.getFirst(); node != null; node = (FieldIndex) node.getNext() ) {
+ if ( node.getIndex() == index ) {
+ return node;
+ }
+ }
+
+ return null;
+ }
+
+ public void propagateAssertObject(final InternalFactHandle handle,
+ final PropagationContext context,
+ final InternalWorkingMemory workingMemory) {
+ final Object object = handle.getObject();
+
+ // Iterates t he FieldIndex collection, which tells you if particularly field is hashed or not
+ // if the field is hashed then it builds the hashkey to return the correct sink for the current objects slot's
+ // value, one object may have multiple fields indexed.
+ if ( this.hashedFieldIndexes != null ) {
+ // Iterate the FieldIndexes to see if any are hashed
+ for ( FieldIndex fieldIndex = (FieldIndex) this.hashedFieldIndexes.getFirst(); fieldIndex != null; fieldIndex = (FieldIndex) fieldIndex.getNext() ) {
+ if ( !fieldIndex.isHashed() ) {
+ continue;
+ }
+ // this field is hashed so set the existing hashKey and see if there is a sink for it
+ final int index = fieldIndex.getIndex();
+ final FieldExtractor extractor = fieldIndex.getFieldExtactor();
+ this.hashKey.setValue( index,
+ object,
+ extractor );
+ final ObjectSink sink = (ObjectSink) this.hashedSinkMap.get( this.hashKey );
+ if ( sink != null ) {
+ // The sink exists so propagate
+ sink.assertObject( handle,
+ context,
+ workingMemory );
+ }
+ }
+ }
+
+ // propagate unhashed
+ if ( this.hashableSinks != null ) {
+ for ( ObjectSinkNode sink = this.hashableSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
+ sink.assertObject( handle,
+ context,
+ workingMemory );
+ }
+ }
+
+ if ( this.otherSinks != null ) {
+ // propagate others
+ for ( ObjectSinkNode sink = this.otherSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
+ sink.assertObject( handle,
+ context,
+ workingMemory );
+ }
+ }
+
+ }
+
+ public void propagateRetractObject(final InternalFactHandle handle,
+ final PropagationContext context,
+ final InternalWorkingMemory workingMemory,
+ final boolean useHash) {
+ if ( this.hashedFieldIndexes != null ) {
+ if ( useHash && this.hashedSinkMap != null ) {
+ final Object object = handle.getObject();
+ // Iterate the FieldIndexes to see if any are hashed
+ for ( FieldIndex fieldIndex = (FieldIndex) this.hashedFieldIndexes.getFirst(); fieldIndex != null; fieldIndex = (FieldIndex) fieldIndex.getNext() ) {
+ // this field is hashed so set the existing hashKey and see if there is a sink for it
+ if ( !fieldIndex.isHashed() ) {
+ continue;
+ }
+
+ final int index = fieldIndex.getIndex();
+ final FieldExtractor extractor = fieldIndex.getFieldExtactor();
+ this.hashKey.setValue( index,
+ object,
+ extractor );
+ final ObjectSink sink = (ObjectSink) this.hashedSinkMap.get( this.hashKey );
+ if ( sink != null ) {
+ // The sink exists so propagate
+ sink.retractObject( handle,
+ context,
+ workingMemory );
+ }
+ }
+ } else if ( this.hashedSinkMap != null ) {
+ final Iterator it = this.hashedSinkMap.newIterator();
+ for ( ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next() ) {
+ final ObjectSink sink = (ObjectSink) entry.getValue();
+ sink.retractObject( handle,
+ context,
+ workingMemory );
+ }
+ }
+ }
+
+ if ( this.hashableSinks != null ) {
+ // we can't retrieve hashed sinks, as the field value might have changed, so we have to iterate and propagate to all hashed sinks
+ for ( ObjectSinkNode sink = this.hashableSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
+ sink.retractObject( handle,
+ context,
+ workingMemory );
+ }
+ }
+
+ if ( this.otherSinks != null ) {
+ // propagate others
+ for ( ObjectSinkNode sink = this.otherSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
+ sink.retractObject( handle,
+ context,
+ workingMemory );
+ }
+ }
+ }
+
+ public ObjectSink[] getSinks() {
+ final List list = new ArrayList();
+
+ if ( this.otherSinks != null ) {
+ for ( ObjectSinkNode sink = this.otherSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
+ list.add( sink );
+ }
+ }
+
+ if ( this.hashableSinks != null ) {
+ for ( ObjectSinkNode sink = this.hashableSinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
+ list.add( sink );
+ }
+ }
+
+ if ( this.hashedSinkMap != null ) {
+ final Iterator it = this.hashedSinkMap.newIterator();
+ for ( ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next() ) {
+ final ObjectSink sink = (ObjectSink) entry.getValue();
+ list.add( sink );
+ }
+ }
+
+ return (ObjectSink[]) list.toArray( new ObjectSink[list.size()] );
+ }
+
+ public int size() {
+ int size = 0;
+ size += ((this.otherSinks != null) ? this.otherSinks.size() : 0);
+ size += ((this.hashableSinks != null) ? this.hashableSinks.size() : 0);
+ size += ((this.hashedSinkMap != null) ? this.hashedSinkMap.size() : 0);
+ return size;
+ }
+
+ public static class HashKey
+ implements
+ Serializable {
+ private static final long serialVersionUID = 400L;
+
+ private static final byte OBJECT = 1;
+ private static final byte LONG = 2;
+ private static final byte DOUBLE = 3;
+ private static final byte BOOL = 4;
+
+ private int index;
+
+ private byte type;
+ private Object ovalue;
+ private long lvalue;
+ private boolean bvalue;
+ private double dvalue;
+
+ private boolean isNull;
+
+ private int hashCode;
+
+ public HashKey() {
+ }
+
+ public HashKey(final int index,
+ final FieldValue value) {
+ this.setValue( index,
+ value );
+ }
+
+ public HashKey(final int index,
+ final Object value,
+ final Extractor extractor) {
+ this.setValue( index,
+ value,
+ extractor );
+ }
+
+ public int getIndex() {
+ return this.index;
+ }
+
+ public void setValue(final int index,
+ final Object value,
+ final Extractor extractor) {
+ this.index = index;
+ final ValueType vtype = extractor.getValueType();
+
+ isNull = extractor.isNullValue(null, value);
+
+ if ( vtype.isBoolean() ) {
+ this.type = BOOL;
+ if ( !isNull ) {
+ this.bvalue = extractor.getBooleanValue( null, value );
+ this.setHashCode( this.bvalue ? 1231 : 1237 );
+ } else {
+ this.setHashCode( 0 );
+ }
+ } else if ( vtype.isIntegerNumber() ) {
+ this.type = LONG;
+ if ( !isNull ) {
+ this.lvalue = extractor.getLongValue( null, value );
+ this.setHashCode( (int) (this.lvalue ^ (this.lvalue >>> 32)) );
+ } else {
+ this.setHashCode( 0 );
+ }
+ } else if ( vtype.isFloatNumber() ) {
+ this.type = DOUBLE;
+ if ( !isNull ) {
+ this.dvalue = extractor.getDoubleValue( null, value );
+ final long temp = Double.doubleToLongBits( this.dvalue );
+ this.setHashCode( (int) (temp ^ (temp >>> 32)) );
+ } else {
+ this.setHashCode( 0 );
+ }
+ } else {
+ this.type = OBJECT;
+ if ( !isNull ) {
+ this.ovalue = extractor.getValue( null, value );
+ this.setHashCode( this.ovalue != null ? this.ovalue.hashCode() : 0 );
+ } else {
+ this.setHashCode( 0 );
+ }
+ }
+ }
+
+ public void setValue(final int index,
+ final FieldValue value) {
+ this.index = index;
+
+ this.isNull = value.isNull();
+
+ if ( value.isBooleanField() ) {
+ this.type = BOOL;
+ if ( !isNull ) {
+ this.bvalue = value.getBooleanValue();
+ this.setHashCode( this.bvalue ? 1231 : 1237 );
+ } else {
+ this.setHashCode( 0 );
+ }
+ } else if ( value.isIntegerNumberField() ) {
+ this.type = LONG;
+ if ( !isNull ) {
+ this.lvalue = value.getLongValue();
+ this.setHashCode( (int) (this.lvalue ^ (this.lvalue >>> 32)) );
+ } else {
+ this.setHashCode( 0 );
+ }
+ } else if ( value.isFloatNumberField() ) {
+ this.type = DOUBLE;
+ if ( !isNull ) {
+ this.dvalue = value.getDoubleValue();
+ final long temp = Double.doubleToLongBits( this.dvalue );
+ this.setHashCode( (int) (temp ^ (temp >>> 32)) );
+ } else {
+ this.setHashCode( 0 );
+ }
+ } else {
+ this.type = OBJECT;
+ if ( !isNull ) {
+ this.ovalue = value.getValue();
+ this.setHashCode( this.ovalue != null ? this.ovalue.hashCode() : 0 );
+ } else {
+ this.setHashCode( 0 );
+ }
+ }
+ }
+
+ private void setHashCode(final int hashSeed) {
+ final int PRIME = 31;
+ int result = 1;
+ result = PRIME * result + hashSeed;
+ result = PRIME * result + this.index;
+ this.hashCode = result;
+ }
+
+ public boolean getBooleanValue() {
+ switch ( this.type ) {
+ case BOOL :
+ return this.bvalue;
+ case OBJECT :
+ if ( this.ovalue == null ) {
+ return false;
+ } else if ( this.ovalue instanceof Boolean ) {
+ return ((Boolean) this.ovalue).booleanValue();
+ } else if ( this.ovalue instanceof String ) {
+ return Boolean.valueOf( (String) this.ovalue ).booleanValue();
+ } else {
+ throw new ClassCastException( "Can't convert " + this.ovalue.getClass() + " to a boolean value." );
+ }
+ case LONG :
+ throw new ClassCastException( "Can't convert long to a boolean value." );
+ case DOUBLE :
+ throw new ClassCastException( "Can't convert double to a boolean value." );
+
+ }
+ return false;
+ }
+
+ public long getLongValue() {
+ switch ( this.type ) {
+ case BOOL :
+ return this.bvalue ? 1 : 0;
+ case OBJECT :
+ if ( this.ovalue == null ) {
+ return 0;
+ } else if ( this.ovalue instanceof Number ) {
+ return ((Number) this.ovalue).longValue();
+ } else if ( this.ovalue instanceof String ) {
+ return Long.parseLong( (String) this.ovalue );
+ } else {
+ throw new ClassCastException( "Can't convert " + this.ovalue.getClass() + " to a long value." );
+ }
+ case LONG :
+ return this.lvalue;
+ case DOUBLE :
+ return (long) this.dvalue;
+
+ }
+ return 0;
+ }
+
+ public double getDoubleValue() {
+ switch ( this.type ) {
+ case BOOL :
+ return this.bvalue ? 1 : 0;
+ case OBJECT :
+ if ( this.ovalue == null ) {
+ return 0;
+ } else if ( this.ovalue instanceof Number ) {
+ return ((Number) this.ovalue).doubleValue();
+ } else if ( this.ovalue instanceof String ) {
+ return Double.parseDouble( (String) this.ovalue );
+ } else {
+ throw new ClassCastException( "Can't convert " + this.ovalue.getClass() + " to a double value." );
+ }
+ case LONG :
+ return this.lvalue;
+ case DOUBLE :
+ return this.dvalue;
+ }
+ return 0;
+ }
+
+ public Object getObjectValue() {
+ switch ( this.type ) {
+ case BOOL :
+ return this.bvalue ? Boolean.TRUE : Boolean.FALSE;
+ case OBJECT :
+ return this.ovalue;
+ case LONG :
+ return new Long( this.lvalue );
+ case DOUBLE :
+ return new Double( this.dvalue );
+ }
+ return null;
+ }
+
+ public int hashCode() {
+ return this.hashCode;
+ }
+
+ public boolean equals(final Object object) {
+ final HashKey other = (HashKey) object;
+
+ if ( this.isNull ) {
+ return ( other.isNull );
+ }
+
+ switch ( this.type ) {
+ case BOOL :
+ return (this.index == other.index) && (this.bvalue == other.getBooleanValue());
+ case LONG :
+ return (this.index == other.index) && (this.lvalue == other.getLongValue());
+ case DOUBLE :
+ return (this.index == other.index) && (this.dvalue == other.getDoubleValue());
+ case OBJECT :
+ final Object otherValue = other.getObjectValue();
+ if ( (this.ovalue != null) && (this.ovalue instanceof Number) && (otherValue instanceof Number) ) {
+ return (this.index == other.index) && (((Number) this.ovalue).doubleValue() == ((Number) otherValue).doubleValue());
+ }
+ return (this.index == other.index) && ( this.ovalue == null ? otherValue == null : this.ovalue.equals( otherValue ));
+ }
+ return false;
+ }
+
+ }
+
+ public static class FieldIndex
+ implements
+ LinkedListNode {
+ private static final long serialVersionUID = 400L;
+ private final int index;
+ private FieldExtractor fieldExtactor;
+
+ private int count;
+
+ private boolean hashed;
+
+ private LinkedListNode previous;
+ private LinkedListNode next;
+
+ public FieldIndex(final int index,
+ final FieldExtractor fieldExtractor) {
+ this.index = index;
+ this.fieldExtactor = fieldExtractor;
+ }
+
+ public FieldExtractor getFieldExtractor() {
+ return this.fieldExtactor;
+ }
+
+ public int getIndex() {
+ return this.index;
+ }
+
+ public int getCount() {
+ return this.count;
+ }
+
+ public FieldExtractor getFieldExtactor() {
+ return this.fieldExtactor;
+ }
+
+ public boolean isHashed() {
+ return this.hashed;
+ }
+
+ public void setHashed(final boolean hashed) {
+ this.hashed = hashed;
+ }
+
+ public void increaseCounter() {
+ this.count++;
+ }
+
+ public void decreaseCounter() {
+ this.count--;
+ }
+
+ public LinkedListNode getNext() {
+ return this.next;
+ }
+
+ public LinkedListNode getPrevious() {
+ return this.previous;
+ }
+
+ public void setNext(final LinkedListNode next) {
+ this.next = next;
+
+ }
+
+ public void setPrevious(final LinkedListNode previous) {
+ this.previous = previous;
+ }
+ }
+}
More information about the jboss-svn-commits
mailing list