From 4b672795338ae517f15fa8e6c9ce0a17dd13ed39 Mon Sep 17 00:00:00 2001
From: mariofusco
Date: Wed, 9 Oct 2013 19:29:03 +0200
Subject: [PATCH] [DROOLS-293] Out of order RightTuples when adding rules
dynamically
---
.../DynamicRulesChangesTest.java | 6 +-
.../integrationtests/DynamicRulesTest.java | 220 +++++++++++++++++-
.../org/drools/reteoo/MockLeftTupleSink.java | 3 +
.../main/java/org/drools/common/BaseNode.java | 13 ++
.../java/org/drools/common/NetworkNode.java | 2 +
.../marshalling/impl/InputMarshaller.java | 7 +-
.../marshalling/impl/OutputMarshaller.java | 5 +-
.../impl/ProtobufOutputMarshaller.java | 2 +-
.../java/org/drools/reteoo/AlphaNode.java | 29 ++-
.../main/java/org/drools/reteoo/BetaNode.java | 35 ++-
.../drools/reteoo/ConditionalBranchNode.java | 16 +-
.../org/drools/reteoo/EntryPointNode.java | 25 +-
.../org/drools/reteoo/EvalConditionNode.java | 16 +-
.../java/org/drools/reteoo/ExistsNode.java | 4 +-
.../main/java/org/drools/reteoo/FromNode.java | 18 +-
.../drools/reteoo/LeftInputAdapterNode.java | 27 +--
.../java/org/drools/reteoo/NodeTypeEnums.java | 9 +-
.../main/java/org/drools/reteoo/NotNode.java | 8 +-
.../org/drools/reteoo/ObjectTypeNode.java | 64 +++--
.../drools/reteoo/PropagationQueuingNode.java | 8 +
.../org/drools/reteoo/QueryElementNode.java | 16 +-
.../org/drools/reteoo/QueryRiaFixerNode.java | 21 +-
.../org/drools/reteoo/QueryTerminalNode.java | 12 +-
.../src/main/java/org/drools/reteoo/Rete.java | 10 +-
.../java/org/drools/reteoo/ReteooBuilder.java | 2 +-
.../drools/reteoo/RightInputAdapterNode.java | 16 +-
.../org/drools/reteoo/RuleTerminalNode.java | 13 +-
.../java/org/drools/reteoo/WindowNode.java | 22 +-
.../drools/reteoo/builder/BuildContext.java | 7 +-
.../org/drools/reteoo/builder/BuildUtils.java | 2 +-
.../builder/ConditionalBranchBuilder.java | 2 +-
.../builder/NamedConsequenceBuilder.java | 19 +-
.../drools/reteoo/builder/PatternBuilder.java | 8 +-
.../reteoo/builder/ReteooRuleBuilder.java | 33 ++-
.../java/org/drools/reteoo/BaseNodeTest.java | 6 +
.../org/drools/reteoo/MockLeftTupleSink.java | 3 +
.../org/drools/reteoo/MockObjectSource.java | 10 +-
.../org/drools/reteoo/MockTupleSource.java | 6 +
.../test/java/org/drools/reteoo/ReteTest.java | 13 +-
39 files changed, 480 insertions(+), 258 deletions(-)
diff --git a/drools-compiler/src/test/java/org/drools/integrationtests/DynamicRulesChangesTest.java b/drools-compiler/src/test/java/org/drools/integrationtests/DynamicRulesChangesTest.java
index baf5b7ae0be..951810733b9 100644
--- a/drools-compiler/src/test/java/org/drools/integrationtests/DynamicRulesChangesTest.java
+++ b/drools-compiler/src/test/java/org/drools/integrationtests/DynamicRulesChangesTest.java
@@ -43,11 +43,11 @@ public void setUp() throws Exception {
addRule("raiseAlarm");
}
- protected static StatefulKnowledgeSession createKnowledgeSession(KnowledgeBase kbase) {
+ protected static StatefulKnowledgeSession createKnowledgeSession(KnowledgeBase kbase) {
return kbase.newStatefulKnowledgeSession();
}
-
-
+
+
@Test(timeout=10000)
public void testConcurrentRuleAdditions() throws Exception {
parallelExecute(RulesExecutor.getSolvers());
diff --git a/drools-compiler/src/test/java/org/drools/integrationtests/DynamicRulesTest.java b/drools-compiler/src/test/java/org/drools/integrationtests/DynamicRulesTest.java
index d48f56a4ec0..cc32c506d33 100644
--- a/drools-compiler/src/test/java/org/drools/integrationtests/DynamicRulesTest.java
+++ b/drools-compiler/src/test/java/org/drools/integrationtests/DynamicRulesTest.java
@@ -28,6 +28,7 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
@@ -35,8 +36,10 @@
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import org.drools.Cheese;
@@ -69,9 +72,15 @@
import org.drools.definition.KnowledgePackage;
import org.drools.definition.type.FactType;
import org.drools.definitions.impl.KnowledgePackageImp;
+import org.drools.event.rule.ActivationCancelledEvent;
import org.drools.event.rule.ActivationCreatedEvent;
import org.drools.event.rule.AfterActivationFiredEvent;
import org.drools.event.rule.AgendaEventListener;
+import org.drools.event.rule.AgendaGroupPoppedEvent;
+import org.drools.event.rule.AgendaGroupPushedEvent;
+import org.drools.event.rule.BeforeActivationFiredEvent;
+import org.drools.event.rule.RuleFlowGroupActivatedEvent;
+import org.drools.event.rule.RuleFlowGroupDeactivatedEvent;
import org.drools.impl.EnvironmentFactory;
import org.drools.io.ResourceFactory;
import org.drools.marshalling.ObjectMarshallingStrategy;
@@ -83,6 +92,7 @@
import org.drools.runtime.EnvironmentName;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.runtime.StatelessKnowledgeSession;
+import org.drools.runtime.rule.Variable;
import org.drools.runtime.rule.WorkingMemoryEntryPoint;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -1065,6 +1075,73 @@ public void testRuleBaseAddRemoveSubNetworks() throws Exception {
}
}
+
+ @Test
+ public void testRuleBaseAddRemoveQuery() throws Exception {
+ try {
+ String drl = "package org.drools.test; \n" +
+ "global java.util.List list; \n" +
+ "query foo( String $s ) $s := String() end \n" +
+ "" +
+ "rule R when String() ?foo( $s ; ) then list.add( $s ); end \n";
+
+ RuleBase ruleBase = RuleBaseFactory.newRuleBase();
+ StatefulSession sf = ruleBase.newStatefulSession();
+ ArrayList list = new ArrayList();
+
+ //add and remove
+ PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( new ByteArrayInputStream( drl.getBytes() ) ) );
+ Package pkg = builder.getPackage();
+ ruleBase.addPackage( pkg );
+
+ sf.setGlobal( "list", list );
+ sf.fireAllRules();
+ sf.insert( "bar" );
+ sf.fireAllRules();
+
+ org.drools.QueryResults rs = sf.getQueryResults( "foo", Variable.v );
+ assertEquals( 1, rs.size() );
+ assertEquals( Arrays.asList( "bar" ), list );
+
+ ruleBase.removePackage( pkg.getName() );
+
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ fail( "Should not raise any exception" );
+ }
+ }
+
+ @Test
+ public void testRuleBaseAddRemoveEval() throws Exception {
+ try {
+ String drl = "package org.drools.test; \n" +
+ "global java.util.List list; \n" +
+ "rule R when $s : String() from \"bar\" eval( $s.length() > 0 ) then list.add( $s ); end \n";
+
+ RuleBase ruleBase = RuleBaseFactory.newRuleBase();
+ StatefulSession sf = ruleBase.newStatefulSession();
+ ArrayList list = new ArrayList();
+
+ //add and remove
+ PackageBuilder builder = new PackageBuilder();
+ builder.addPackageFromDrl( new InputStreamReader( new ByteArrayInputStream( drl.getBytes() ) ) );
+ Package pkg = builder.getPackage();
+ ruleBase.addPackage( pkg );
+
+ sf.setGlobal( "list", list );
+ sf.fireAllRules();
+ assertEquals( Arrays.asList( "bar" ), list );
+
+ ruleBase.removePackage( pkg.getName() );
+
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ fail( "Should not raise any exception" );
+ }
+ }
+
+
@Test
public void testDynamicRuleAdditionsWithEntryPoints() throws Exception {
Reader reader = new InputStreamReader( getClass().getResourceAsStream( "test_DynamicWithEntryPoint.drl" ) );
@@ -1362,9 +1439,23 @@ public void testJBRULES_2206() {
((RuleBaseConfiguration) config).setRuleBaseUpdateHandler( null );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase( config );
StatefulKnowledgeSession session = createKnowledgeSession(kbase);
-
+
AgendaEventListener ael = mock( AgendaEventListener.class );
session.addEventListener( ael );
+ session.addEventListener( new AgendaEventListener() {
+ public void activationCreated( ActivationCreatedEvent activationCreatedEvent ) {
+ System.out.println( activationCreatedEvent );
+ }
+ public void activationCancelled( ActivationCancelledEvent activationCancelledEvent ) { }
+ public void beforeActivationFired( BeforeActivationFiredEvent beforeActivationFiredEvent ) {}
+ public void afterActivationFired( AfterActivationFiredEvent afterActivationFiredEvent ) {}
+ public void agendaGroupPopped( AgendaGroupPoppedEvent agendaGroupPoppedEvent ) {}
+ public void agendaGroupPushed( AgendaGroupPushedEvent agendaGroupPushedEvent ) {}
+ public void beforeRuleFlowGroupActivated( RuleFlowGroupActivatedEvent ruleFlowGroupActivatedEvent ) {}
+ public void afterRuleFlowGroupActivated( RuleFlowGroupActivatedEvent ruleFlowGroupActivatedEvent ) {}
+ public void beforeRuleFlowGroupDeactivated( RuleFlowGroupDeactivatedEvent ruleFlowGroupDeactivatedEvent ) {}
+ public void afterRuleFlowGroupDeactivated( RuleFlowGroupDeactivatedEvent ruleFlowGroupDeactivatedEvent ) {}
+ } );
for ( int i = 0; i < 5; i++ ) {
session.insert( new Cheese() );
@@ -1427,4 +1518,131 @@ protected synchronized Class loadClass(String name,
return c;
}
}
+
+
+
+ @Test
+ public void testDynamicRulesWithInheritance() {
+ String type = "package com.sample\n" +
+ "global java.util.List list; \n" +
+ "declare Foo\n" +
+ " id : int\n" +
+ "end\n" +
+ "" +
+ "declare Bar extends Foo end\n" +
+ "";
+
+ String r1 = "package com.sample\n" +
+ "global java.util.List list; \n" +
+ "rule R1 when\n" +
+ " Bar()\n" +
+ "then\n" +
+ " list.add( 1 ); \n" +
+ "end \n" +
+ "" +
+ "rule Init when \n" +
+ "then \n" +
+ " insert( new Bar() );\n" +
+ "end\n";
+
+ String r2 = "package com.sample\n" +
+ "global java.util.List list; \n" +
+ "rule R2 when\n" +
+ " $f : Foo()\n" +
+ "then\n" +
+ " list.add( 2 );\n" +
+ "end\n";
+
+ KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+ kbuilder.add( ResourceFactory.newByteArrayResource( type.getBytes() ), ResourceType.DRL );
+ assertFalse( kbuilder.getErrors().toString(), kbuilder.hasErrors() );
+
+ KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+ kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
+
+ StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
+ ArrayList list = new ArrayList();
+ ksession.setGlobal( "list", list );
+
+ kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder( kbase );
+ kbuilder.add( ResourceFactory.newByteArrayResource( r1.getBytes() ), ResourceType.DRL );
+ assertFalse( kbuilder.getErrors().toString(), kbuilder.hasErrors() );
+
+ ksession.fireAllRules();
+ assertEquals( Arrays.asList( 1 ), list );
+
+ kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder( kbase );
+ kbuilder.add( ResourceFactory.newByteArrayResource( r2.getBytes() ), ResourceType.DRL );
+ assertFalse( kbuilder.getErrors().toString(), kbuilder.hasErrors() );
+
+ ksession.fireAllRules();
+ assertEquals( Arrays.asList( 1, 2 ), list );
+
+ ksession.dispose();
+
+ }
+
+
+
+ @Test
+ public void testDynamicRulesWithNamedConsequencesAndConditionalBranches() {
+ String type = "package com.sample\n" +
+ "declare type Foo\n" +
+ " id : int\n" +
+ "end\n" +
+ "" +
+ "rule Init when then \n" +
+ " insert( new Foo( 1 ) ); \n" +
+ " insert( new Foo( 2 ) ); \n" +
+ "end \n";
+
+ String r1 = "package com.sample\n" +
+ "global java.util.Set set; \n" +
+ "rule R1 when\n" +
+ " $s: String() do[c1] \n" +
+ " Foo( $i : id ) do[c2] \n" +
+ " if ( id == 1 ) do[c3] \n" +
+ " else do[c4]" +
+ "then\n" +
+ " set.add( $i ); \n" +
+ "then[c1] \n" +
+ " set.add( $s ); \n" +
+ "then[c2] \n" +
+ " set.add( 100 + $i ); \n" +
+ "then[c3] \n" +
+ " set.add( 200 + $i ); \n" +
+ "then[c4] \n" +
+ " set.add( 300 + $i ); \n" +
+ "end\n";
+
+ KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+ kbuilder.add( ResourceFactory.newByteArrayResource( type.getBytes() ), ResourceType.DRL );
+ assertFalse( kbuilder.getErrors().toString(), kbuilder.hasErrors() );
+
+ KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+ kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
+
+ StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
+
+ ksession.fireAllRules();
+
+ kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder( kbase );
+ kbuilder.add( ResourceFactory.newByteArrayResource( r1.getBytes() ), ResourceType.DRL );
+ assertFalse( kbuilder.getErrors().toString(), kbuilder.hasErrors() );
+ kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
+
+ HashSet set = new HashSet();
+ ksession.setGlobal( "set", set );
+ ksession.insert( "go" );
+
+ ksession.fireAllRules();
+
+ System.out.print( set );
+ assertTrue( set.containsAll( Arrays.asList( 1, 2, 101, 201, 102, 302, "go" ) ) );
+
+ ksession.dispose();
+
+ }
+
+
}
diff --git a/drools-compiler/src/test/java/org/drools/reteoo/MockLeftTupleSink.java b/drools-compiler/src/test/java/org/drools/reteoo/MockLeftTupleSink.java
index 05121ba1a8b..173023ee392 100644
--- a/drools-compiler/src/test/java/org/drools/reteoo/MockLeftTupleSink.java
+++ b/drools-compiler/src/test/java/org/drools/reteoo/MockLeftTupleSink.java
@@ -103,6 +103,9 @@ public void attach(BuildContext buildContext) {
}
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ }
+
public List getPropagatedTuples(final ReteooWorkingMemory workingMemory,
final LeftTupleSink sink) {
// TODO Auto-generated method stub
diff --git a/drools-core/src/main/java/org/drools/common/BaseNode.java b/drools-core/src/main/java/org/drools/common/BaseNode.java
index e1399d8deb6..cd349128209 100644
--- a/drools-core/src/main/java/org/drools/common/BaseNode.java
+++ b/drools-core/src/main/java/org/drools/common/BaseNode.java
@@ -22,6 +22,7 @@
import org.drools.reteoo.ReteooBuilder;
import org.drools.reteoo.RuleRemovalContext;
import org.drools.reteoo.builder.BuildContext;
+import org.drools.spi.PropagationContext;
import org.drools.spi.RuleComponent;
import java.io.IOException;
@@ -94,6 +95,18 @@ public void attach() {
*/
public abstract void attach(BuildContext context);
+ public abstract void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory );
+
+ public void updateSinkOnAttach( BuildContext context, InternalWorkingMemory workingMemory ) {
+ final PropagationContext propagationContext = new PropagationContextImpl(workingMemory.getNextPropagationIdCounter(),
+ PropagationContext.RULE_ADDITION,
+ null,
+ null,
+ null);
+ this.updateSinkOnAttach( context, propagationContext, workingMemory );
+ propagationContext.evaluateActionQueue( workingMemory );
+ }
+
/**
* A method that is called for all nodes whose network below them
* changed, after the change is complete, providing them with an oportunity
diff --git a/drools-core/src/main/java/org/drools/common/NetworkNode.java b/drools-core/src/main/java/org/drools/common/NetworkNode.java
index f9f0ec07108..752388c6968 100644
--- a/drools-core/src/main/java/org/drools/common/NetworkNode.java
+++ b/drools-core/src/main/java/org/drools/common/NetworkNode.java
@@ -42,4 +42,6 @@ public interface NetworkNode
*/
public RuleBasePartitionId getPartitionId();
+ public short getType();
+
}
diff --git a/drools-core/src/main/java/org/drools/marshalling/impl/InputMarshaller.java b/drools-core/src/main/java/org/drools/marshalling/impl/InputMarshaller.java
index 931aeb0f4b2..527cf800479 100644
--- a/drools-core/src/main/java/org/drools/marshalling/impl/InputMarshaller.java
+++ b/drools-core/src/main/java/org/drools/marshalling/impl/InputMarshaller.java
@@ -77,7 +77,6 @@
import org.drools.reteoo.ObjectTypeNode;
import org.drools.reteoo.QueryElementNode;
import org.drools.reteoo.QueryElementNode.UnificationNodeViewChangedEventListener;
-import org.drools.reteoo.ReteooComponentFactory;
import org.drools.reteoo.ReteooStatefulSession;
import org.drools.reteoo.ReteooWorkingMemory;
import org.drools.reteoo.RightTuple;
@@ -268,6 +267,7 @@ public static ReteooStatefulSession readSession( ReteooStatefulSession session,
try {
// Yeah, I know, because one session is being deserialized, we go and lock all of them...
initialFactNode.attach( buildContext );
+ initialFactNode.updateSinkOnAttach( buildContext, context.wm );
} finally {
context.ruleBase.unlock();
}
@@ -659,8 +659,7 @@ public static void readLeftTuple( LeftTuple parentLeftTuple,
}
break;
}
- case NodeTypeEnums.NotNode:
- case NodeTypeEnums.ForallNotNode: {
+ case NodeTypeEnums.NotNode: {
BetaMemory memory = (BetaMemory) context.wm.getNodeMemory( (BetaNode) sink );
int type = stream.readShort();
if (type == PersisterEnums.LEFT_TUPLE_NOT_BLOCKED) {
@@ -768,7 +767,7 @@ public static void readLeftTuple( LeftTuple parentLeftTuple,
}
break;
}
- case NodeTypeEnums.RightInputAdaterNode: {
+ case NodeTypeEnums.RightInputAdapterNode: {
// RIANs generate new fact handles on-demand to wrap tuples and need special procedures when de-serializing from persistent storage
ObjectHashMap memory = (ObjectHashMap) context.wm.getNodeMemory( (NodeMemory) sink );
// create fact handle
diff --git a/drools-core/src/main/java/org/drools/marshalling/impl/OutputMarshaller.java b/drools-core/src/main/java/org/drools/marshalling/impl/OutputMarshaller.java
index 57335c07a8e..46b91991d08 100644
--- a/drools-core/src/main/java/org/drools/marshalling/impl/OutputMarshaller.java
+++ b/drools-core/src/main/java/org/drools/marshalling/impl/OutputMarshaller.java
@@ -605,8 +605,7 @@ public static void writeLeftTuple(LeftTuple leftTuple,
//context.out.println( "---- EvalConditionNode --- END" );
break;
}
- case NodeTypeEnums.NotNode :
- case NodeTypeEnums.ForallNotNode : {
+ case NodeTypeEnums.NotNode : {
if ( leftTuple.getBlocker() == null ) {
// is not blocked so has children
stream.writeShort( PersisterEnums.LEFT_TUPLE_NOT_BLOCKED );
@@ -682,7 +681,7 @@ public static void writeLeftTuple(LeftTuple leftTuple,
//context.out.println( "---- AccumulateNode --- END" );
break;
}
- case NodeTypeEnums.RightInputAdaterNode : {
+ case NodeTypeEnums.RightInputAdapterNode : {
//context.out.println( ".... RightInputAdapterNode" );
// RIANs generate new fact handles on-demand to wrap tuples and need special procedures when serializing to persistent storage
ObjectHashMap memory = (ObjectHashMap) context.wm.getNodeMemory( (NodeMemory) sink );
diff --git a/drools-core/src/main/java/org/drools/marshalling/impl/ProtobufOutputMarshaller.java b/drools-core/src/main/java/org/drools/marshalling/impl/ProtobufOutputMarshaller.java
index 8e2d17b78c6..bc37b458955 100644
--- a/drools-core/src/main/java/org/drools/marshalling/impl/ProtobufOutputMarshaller.java
+++ b/drools-core/src/main/java/org/drools/marshalling/impl/ProtobufOutputMarshaller.java
@@ -297,7 +297,7 @@ private static void writeNodeMemories(MarshallerWriteContext context,
_node = writeAccumulateNodeMemory(i, memory);
break;
}
- case NodeTypeEnums.RightInputAdaterNode: {
+ case NodeTypeEnums.RightInputAdapterNode: {
_node = writeRIANodeMemory(i, memory);
break;
}
diff --git a/drools-core/src/main/java/org/drools/reteoo/AlphaNode.java b/drools-core/src/main/java/org/drools/reteoo/AlphaNode.java
index 102c2fc5317..583d61c4027 100644
--- a/drools-core/src/main/java/org/drools/reteoo/AlphaNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/AlphaNode.java
@@ -31,7 +31,6 @@
import org.drools.common.RuleBasePartitionId;
import org.drools.reteoo.builder.BuildContext;
import org.drools.rule.ContextEntry;
-import org.drools.rule.Pattern;
import org.drools.rule.constraint.EvaluatorConstraint;
import org.drools.rule.constraint.MvelConstraint;
import org.drools.runtime.rule.Operator;
@@ -106,6 +105,10 @@ public void writeExternal(ObjectOutput out) throws IOException {
out.writeLong(inferredMask);
}
+ public short getType() {
+ return NodeTypeEnums.AlphaNode;
+ }
+
/**
* Retruns the FieldConstraint
*
@@ -117,22 +120,12 @@ public AlphaNodeFieldConstraint getConstraint() {
public void attach(BuildContext context) {
this.source.addObjectSink( this );
- if (context == null) {
- return;
- }
+ }
+
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ // do nothing, this node's updateSink will be called from the beta network
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
- this.source.updateSink( this,
- propagationContext,
- workingMemory );
- }
- }
-
public void assertObject(final InternalFactHandle factHandle,
final PropagationContext context,
final InternalWorkingMemory workingMemory) {
@@ -338,6 +331,10 @@ public int getId() {
return 0;
}
+ public short getType() {
+ return -1;
+ }
+
public RuleBasePartitionId getPartitionId() {
return this.sink.getPartitionId();
}
diff --git a/drools-core/src/main/java/org/drools/reteoo/BetaNode.java b/drools-core/src/main/java/org/drools/reteoo/BetaNode.java
index 43bb271f8b4..550b0bf3955 100644
--- a/drools-core/src/main/java/org/drools/reteoo/BetaNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/BetaNode.java
@@ -95,7 +95,7 @@ public abstract class BetaNode extends LeftTupleSource
protected boolean tupleMemoryEnabled;
protected boolean concurrentRightTupleMemory = false;
- /** @see LRUnlinkingOption */
+ /** @see org.drools.builder.conf.LRUnlinkingOption */
protected boolean lrUnlinkingEnabled = false;
private boolean indexedUnificationJoin;
@@ -390,17 +390,12 @@ public void attach(BuildContext context) {
this.rightInput.addObjectSink( this );
this.leftInput.addTupleSink( this, context );
+ }
- if (context == null) {
- return;
- }
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl(workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null);
+ boolean leftUpdate = ! context.getNodes().contains( this.getLeftTupleSource() );
+ boolean rightUpdate = this.getRightInput().getType() == NodeTypeEnums.AlphaNode || ! context.getNodes().contains( this.getRightInput() );
/* FIXME: This should be generalized at BetaNode level and the
* instanceof should be removed!
@@ -409,18 +404,18 @@ public void attach(BuildContext context) {
* that is initially linked. If there are tuples to be propagated,
* they will trigger the update (thus, population) of the other side.
* */
- if (!lrUnlinkingEnabled || !(this instanceof JoinNode)) {
+ if ( ! lrUnlinkingEnabled && rightUpdate) {
- this.rightInput.updateSink(this,
- propagationContext,
- workingMemory);
- }
+ this.rightInput.updateSink(this,
+ propagationContext,
+ workingMemory);
+ }
+ if ( leftUpdate ) {
this.leftInput.updateSink(this,
- propagationContext,
- workingMemory);
+ propagationContext,
+ workingMemory);
}
-
}
protected void doRemove(final RuleRemovalContext context,
@@ -775,4 +770,8 @@ public ObjectTypeNode.Id getRightInputOtnId() {
public void setRightInputOtnId(ObjectTypeNode.Id rightInputOtnId) {
this.rightInputOtnId = rightInputOtnId;
}
+
+ public ObjectSource getRightInput() {
+ return rightInput;
+ }
}
diff --git a/drools-core/src/main/java/org/drools/reteoo/ConditionalBranchNode.java b/drools-core/src/main/java/org/drools/reteoo/ConditionalBranchNode.java
index 999ac80323b..c70e34ed014 100644
--- a/drools-core/src/main/java/org/drools/reteoo/ConditionalBranchNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/ConditionalBranchNode.java
@@ -67,20 +67,10 @@ public void writeExternal(ObjectOutput out) throws IOException {
public void attach( BuildContext context ) {
this.tupleSource.addTupleSink(this, context);
- if (context == null) {
- return;
- }
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
- this.tupleSource.updateSink( this,
- propagationContext,
- workingMemory );
- }
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ // do nothing, this node's updateSink will be called from the Beta Network??
}
public void networkUpdated(UpdateContext updateContext) {
diff --git a/drools-core/src/main/java/org/drools/reteoo/EntryPointNode.java b/drools-core/src/main/java/org/drools/reteoo/EntryPointNode.java
index 834f2132696..93a4c10a266 100644
--- a/drools-core/src/main/java/org/drools/reteoo/EntryPointNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/EntryPointNode.java
@@ -125,6 +125,10 @@ public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject( objectTypeNodes );
}
+ public short getType() {
+ return NodeTypeEnums.EntryPointNode;
+ }
+
/**
* @return the entryPoint
*/
@@ -399,23 +403,16 @@ protected void removeObjectSink(final ObjectSink objectSink) {
public void attach( BuildContext context ) {
this.source.addObjectSink( this );
- if (context == null) {
- return;
- }
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- workingMemory.updateEntryPointsCache();
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
- this.source.updateSink( this,
- propagationContext,
- workingMemory );
- }
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ workingMemory.updateEntryPointsCache();
+ this.source.updateSink( this,
+ propagationContext,
+ workingMemory );
}
+
protected void doRemove(final RuleRemovalContext context,
final ReteooBuilder builder,
final InternalWorkingMemory[] workingMemories) {
diff --git a/drools-core/src/main/java/org/drools/reteoo/EvalConditionNode.java b/drools-core/src/main/java/org/drools/reteoo/EvalConditionNode.java
index 1675ab28f34..53a18b06ca5 100644
--- a/drools-core/src/main/java/org/drools/reteoo/EvalConditionNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/EvalConditionNode.java
@@ -117,20 +117,10 @@ public void writeExternal(ObjectOutput out) throws IOException {
public void attach( BuildContext context ) {
this.tupleSource.addTupleSink( this, context );
- if (context == null) {
- return;
- }
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
- this.tupleSource.updateSink( this,
- propagationContext,
- workingMemory );
- }
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ // do nothing, this node's updateSink will be called from the beta network
}
public void networkUpdated(UpdateContext updateContext) {
diff --git a/drools-core/src/main/java/org/drools/reteoo/ExistsNode.java b/drools-core/src/main/java/org/drools/reteoo/ExistsNode.java
index 0cc23aa190a..a3023b86267 100755
--- a/drools-core/src/main/java/org/drools/reteoo/ExistsNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/ExistsNode.java
@@ -436,7 +436,7 @@ public void modifyRightTuple(RightTuple rightTuple,
// this is now blocked so remove from memory
leftMemory.remove( leftTuple );
- // subclasses like ForallNotNode might override this propagation
+ // subclasses might override this propagation
this.sink.propagateAssertLeftTuple( leftTuple,
context,
workingMemory,
@@ -497,7 +497,7 @@ public void modifyRightTuple(RightTuple rightTuple,
// was previous blocked and not in memory, so add
memory.getLeftTupleMemory().add( leftTuple );
- // subclasses like ForallNotNode might override this propagation
+ // subclasses might override this propagation
this.sink.propagateRetractLeftTuple( leftTuple,
context,
workingMemory );
diff --git a/drools-core/src/main/java/org/drools/reteoo/FromNode.java b/drools-core/src/main/java/org/drools/reteoo/FromNode.java
index a37ba97b0a4..278758bd944 100644
--- a/drools-core/src/main/java/org/drools/reteoo/FromNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/FromNode.java
@@ -25,7 +25,6 @@
import org.drools.common.InternalRuleBase;
import org.drools.common.InternalWorkingMemory;
import org.drools.common.Memory;
-import org.drools.common.NamedEntryPoint;
import org.drools.common.NodeMemory;
import org.drools.common.PropagationContextImpl;
import org.drools.common.UpdateContext;
@@ -40,7 +39,6 @@
import org.drools.marshalling.impl.ProtobufMessages.FactHandle;
import org.drools.reteoo.builder.BuildContext;
import org.drools.rule.ContextEntry;
-import org.drools.rule.EntryPoint;
import org.drools.rule.From;
import org.drools.spi.AlphaNodeFieldConstraint;
import org.drools.spi.DataProvider;
@@ -406,20 +404,10 @@ private void unlinkCreatedHandles(final InternalWorkingMemory workingMemory,
public void attach( BuildContext context ) {
betaConstraints.init(context, getType());
this.tupleSource.addTupleSink( this, context );
- if (context == null) {
- return;
- }
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
- this.tupleSource.updateSink( this,
- propagationContext,
- workingMemory );
- }
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ // do nothing, this node's updateSink will be called from the beta network
}
public void networkUpdated(UpdateContext updateContext) {
diff --git a/drools-core/src/main/java/org/drools/reteoo/LeftInputAdapterNode.java b/drools-core/src/main/java/org/drools/reteoo/LeftInputAdapterNode.java
index f9473cefe52..16149c6d8a9 100644
--- a/drools-core/src/main/java/org/drools/reteoo/LeftInputAdapterNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/LeftInputAdapterNode.java
@@ -30,13 +30,6 @@
import java.io.ObjectInput;
import java.io.ObjectOutput;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.Map;
-
-import static org.drools.core.util.BitMaskUtil.intersect;
-
/**
* All asserting Facts must propagated into the right ObjectSink
side of a BetaNode, if this is the first Pattern
* then there are no BetaNodes to propagate to. LeftInputAdapter
is used to adapt an ObjectSink propagation into a
@@ -102,6 +95,10 @@ public void writeExternal(ObjectOutput out) throws IOException {
out.writeBoolean( leftTupleMemoryEnabled );
out.writeBoolean( rootQueryNode );
}
+
+ public short getType() {
+ return NodeTypeEnums.LeftInputAdapterNode;
+ }
public boolean isRootQueryNode() {
return this.rootQueryNode;
@@ -113,16 +110,10 @@ public ObjectSource getParentObjectSource() {
public void attach( BuildContext context ) {
this.objectSource.addObjectSink( this );
- if (context == null) {
- return;
- }
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ if ( ! context.getNodes().contains( this.getParentObjectSource() ) || this.getParentObjectSource().getType() == NodeTypeEnums.AlphaNode ) {
this.objectSource.updateSink( this,
propagationContext,
workingMemory );
@@ -303,6 +294,10 @@ public int getId() {
return 0;
}
+ public short getType() {
+ return -1;
+ }
+
public RuleBasePartitionId getPartitionId() {
return sink.getPartitionId();
}
diff --git a/drools-core/src/main/java/org/drools/reteoo/NodeTypeEnums.java b/drools-core/src/main/java/org/drools/reteoo/NodeTypeEnums.java
index 509eab86458..1465bb872a5 100644
--- a/drools-core/src/main/java/org/drools/reteoo/NodeTypeEnums.java
+++ b/drools-core/src/main/java/org/drools/reteoo/NodeTypeEnums.java
@@ -24,10 +24,10 @@ public class NodeTypeEnums {
public static final short FromNode = 4;
//public static final short CollectNode = 5; // no longer used, since accumulate nodes execute collect logic now
public static final short AccumulateNode = 6;
- public static final short RightInputAdaterNode = 7;
+ public static final short RightInputAdapterNode = 7;
public static final short QueryTerminalNode = 8;
public static final short RuleTerminalNode = 9;
- public static final short ForallNotNode = 10;
+
public static final short UnificationNode = 11;
public static final short QueryRiaFixerNode = 12;
public static final short WindowNode = 13;
@@ -35,7 +35,10 @@ public class NodeTypeEnums {
public static final short AlphaNode = 15;
public static final short ObjectTypeNode = 16;
public static final short PropagationQueueingNode = 17;
- public static final short QueryElementNode = 18;
+ public static final short QueryElementNode = 18; // duplicated by UnificationNode ?
public static final short OperatorNode = 19;
public static final short ConditionalBranchNode = 20;
+ public static final short EntryPointNode = 21;
+ public static final short LeftInputAdapterNode = 22;
+
}
diff --git a/drools-core/src/main/java/org/drools/reteoo/NotNode.java b/drools-core/src/main/java/org/drools/reteoo/NotNode.java
index 842c1499de8..5ba0994171d 100644
--- a/drools-core/src/main/java/org/drools/reteoo/NotNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/NotNode.java
@@ -140,7 +140,7 @@ public void assertObject(final InternalFactHandle factHandle,
// this is now blocked so remove from memory
memory.getLeftTupleMemory().remove( leftTuple );
- // subclasses like ForallNotNode might override this propagation
+ // subclasses might override this propagation
propagateRetractLeftTuple( context,
workingMemory,
leftTuple );
@@ -200,7 +200,7 @@ public void retractRightTuple(final RightTuple rightTuple,
// was previous blocked and not in memory, so add
memory.getLeftTupleMemory().add( leftTuple );
- // subclasses like ForallNotNode might override this propagation
+ // subclasses might override this propagation
propagateAssertLeftTuple( context,
workingMemory,
leftTuple );
@@ -368,7 +368,7 @@ public void modifyRightTuple(RightTuple rightTuple,
// this is now blocked so remove from memory
leftMemory.remove( leftTuple );
- // subclasses like ForallNotNode might override this propagation
+ // subclasses might override this propagation
propagateRetractLeftTuple( context,
workingMemory,
leftTuple );
@@ -426,7 +426,7 @@ public void modifyRightTuple(RightTuple rightTuple,
// was previous blocked and not in memory, so add
memory.getLeftTupleMemory().add( leftTuple );
- // subclasses like ForallNotNode might override this propagation
+ // subclasses might override this propagation
propagateAssertLeftTuple( context,
workingMemory,
leftTuple );
diff --git a/drools-core/src/main/java/org/drools/reteoo/ObjectTypeNode.java b/drools-core/src/main/java/org/drools/reteoo/ObjectTypeNode.java
index 1f8608e5dd8..613bf279711 100644
--- a/drools-core/src/main/java/org/drools/reteoo/ObjectTypeNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/ObjectTypeNode.java
@@ -139,7 +139,7 @@ public ObjectTypeNode(final int id,
source,
context.getRuleBase().getConfiguration().getAlphaNodeHashingThreshold() );
this.objectType = objectType;
- idGenerator = new IdGenerator(objectType);
+ idGenerator = new IdGenerator(id);
setObjectMemoryEnabled( context.isObjectTypeNodeMemoryEnabled() );
@@ -151,15 +151,15 @@ public ObjectTypeNode(final int id,
}
private static class IdGenerator {
- private final Class> otnClass;
+ private final int otnId;
private int otnIdCounter;
- private IdGenerator(ObjectType objectType) {
- otnClass = objectType instanceof ClassObjectType ? ((ClassObjectType)objectType).getClassType() : Object.class;
+ private IdGenerator(int otnId) {
+ this.otnId = otnId;
}
private Id nextId() {
- return new Id(otnClass, otnIdCounter++);
+ return new Id(otnId, otnIdCounter++);
}
private void reset() {
@@ -167,21 +167,21 @@ private void reset() {
}
}
- public static Id DEFAULT_ID = new Id(Object.class, 0);
+ public static Id DEFAULT_ID = new Id(-1, 0);
public static class Id {
- private final Class> clazz;
+ private final int otnId;
private final int id;
- public Id(Class> clazz, int id) {
- this.clazz = clazz;
+ public Id(int otnId, int id) {
+ this.otnId = otnId;
this.id = id;
}
@Override
public String toString() {
- return "ObjectTypeNode.Id[" + clazz.getName() + "#" + id + "]";
+ return "ObjectTypeNode.Id[" + otnId + "#" + id + "]";
}
@Override
@@ -190,22 +190,16 @@ public boolean equals(Object o) {
if (o == null || !(o instanceof Id)) return false;
Id otherId = (Id) o;
- return id == otherId.id && clazz == otherId.clazz;
+ return id == otherId.id && otnId == otherId.otnId;
}
@Override
public int hashCode() {
- int result = clazz.hashCode();
- result = 31 * result + id;
- return result;
+ return 31 * otnId + 37 * id;
}
public boolean before(Id otherId) {
- return otherId != null && clazz == otherId.clazz && this.id < otherId.id;
- }
-
- public Class> getTypeNodeClass() {
- return clazz;
+ return otherId != null && (otnId < otherId.otnId || ( otnId == otherId.otnId && id < otherId.id));
}
public int getId() {
@@ -223,13 +217,14 @@ public void readExternal(ObjectInput in) throws IOException,
if ( objectType instanceof ClassObjectType ) {
objectType = ((AbstractRuleBase) ((DroolsObjectInputStream) in).getRuleBase()).getClassFieldAccessorCache().getClassObjectType( (ClassObjectType) objectType );
}
- idGenerator = new IdGenerator(objectType);
objectMemoryEnabled = in.readBoolean();
expirationOffset = in.readLong();
lrUnlinkingEnabled = in.readBoolean();
queryNode = in.readBoolean();
+
dirty = true;
+ idGenerator = new IdGenerator(id);
}
public void writeExternal(ObjectOutput out) throws IOException {
@@ -250,6 +245,10 @@ public ObjectType getObjectType() {
return this.objectType;
}
+ public short getType() {
+ return NodeTypeEnums.ObjectTypeNode;
+ }
+
@Override
public long calculateDeclaredMask(List settableProperties) {
return 0;
@@ -435,24 +434,13 @@ public void updateSink(final ObjectSink sink,
*/
public void attach( BuildContext context ) {
this.source.addObjectSink( this );
- if (context == null) {
- return;
- }
+ }
- // we need to call updateSink on Rete, because someone
- // might have already added facts matching this ObjectTypeNode
- // to working memories
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContextImpl propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
- propagationContext.setEntryPoint( ((EntryPointNode) this.source).getEntryPoint() );
- this.source.updateSink( this,
- propagationContext,
- workingMemory );
- }
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ ((PropagationContextImpl)propagationContext).setEntryPoint( ( (EntryPointNode) this.source ).getEntryPoint() );
+ this.source.updateSink( this,
+ propagationContext,
+ workingMemory );
}
public void networkUpdated(UpdateContext updateContext) {
@@ -558,7 +546,7 @@ public boolean equals(final Object object) {
final ObjectTypeNode other = (ObjectTypeNode) object;
- return this.objectType.equals(other.objectType) && this.source.equals(other.source);
+ return this.objectType.equals( other.objectType ) && this.source.equals( other.source );
}
private boolean usesDeclaration(final Constraint[] constraints) {
diff --git a/drools-core/src/main/java/org/drools/reteoo/PropagationQueuingNode.java b/drools-core/src/main/java/org/drools/reteoo/PropagationQueuingNode.java
index b5c21076c05..f9592c2d9be 100644
--- a/drools-core/src/main/java/org/drools/reteoo/PropagationQueuingNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/PropagationQueuingNode.java
@@ -101,6 +101,10 @@ public void writeExternal( ObjectOutput out ) throws IOException {
out.writeObject( action );
}
+ public short getType() {
+ return NodeTypeEnums.PropagationQueueingNode;
+ }
+
/**
* @see org.drools.reteoo.ObjectSource#updateSink(org.drools.reteoo.ObjectSink, org.drools.spi.PropagationContext, org.drools.common.InternalWorkingMemory)
*/
@@ -126,6 +130,10 @@ public void attach( BuildContext context ) {
// this node does not require update, so nothing else to do.
}
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ // do nothing, this node does not require updates
+ }
+
/**
* @see org.drools.reteoo.ObjectSinkNode#getNextObjectSinkNode()
*/
diff --git a/drools-core/src/main/java/org/drools/reteoo/QueryElementNode.java b/drools-core/src/main/java/org/drools/reteoo/QueryElementNode.java
index 53d25baff91..bc4eb58d5c7 100644
--- a/drools-core/src/main/java/org/drools/reteoo/QueryElementNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/QueryElementNode.java
@@ -143,20 +143,10 @@ protected void doCollectAncestors(NodeSet nodeSet) {
public void attach( BuildContext context ) {
this.tupleSource.addTupleSink( this, context );
- if (context == null) {
- return;
- }
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
- this.tupleSource.updateSink( this,
- propagationContext,
- workingMemory );
- }
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ // do nothing, this node's updateSink will be called from the beta network
}
public void networkUpdated(UpdateContext updateContext) {
diff --git a/drools-core/src/main/java/org/drools/reteoo/QueryRiaFixerNode.java b/drools-core/src/main/java/org/drools/reteoo/QueryRiaFixerNode.java
index 777b54c0c0b..b11f379dbc5 100644
--- a/drools-core/src/main/java/org/drools/reteoo/QueryRiaFixerNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/QueryRiaFixerNode.java
@@ -38,7 +38,6 @@
*
*
* @see QueryRiaFixerNode
- * @see Eval
* @see LeftTuple
*/
public class QueryRiaFixerNode extends LeftTupleSource
@@ -71,11 +70,12 @@ public QueryRiaFixerNode() {
/**
* Construct.
*
- * @param rule
- * The rule
+ * @param id
+ * The node id
* @param tupleSource
* The source of incoming Tuples
.
- * @param eval
+ * @param context
+ * The build context
*/
public QueryRiaFixerNode(final int id,
final LeftTupleSource tupleSource,
@@ -113,16 +113,10 @@ public void addTupleSink(LeftTupleSink tupleSink, BuildContext context) {
public void attach( BuildContext context ) {
this.tupleSource.addTupleSink( this, context );
- if (context == null) {
- return;
- }
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ if ( ! context.getNodes().contains( this.getLeftTupleSource() ) ) {
this.tupleSource.updateSink( this,
propagationContext,
workingMemory );
@@ -148,7 +142,6 @@ public void networkUpdated(UpdateContext updateContext) {
* The Tuple
being asserted.
* @param workingMemory
* The working memory seesion.
- * @throws AssertionException
* If an error occurs while asserting.
*/
public void assertLeftTuple(final LeftTuple leftTuple,
diff --git a/drools-core/src/main/java/org/drools/reteoo/QueryTerminalNode.java b/drools-core/src/main/java/org/drools/reteoo/QueryTerminalNode.java
index b7e1ccd951d..edb974ab946 100644
--- a/drools-core/src/main/java/org/drools/reteoo/QueryTerminalNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/QueryTerminalNode.java
@@ -192,16 +192,10 @@ public String toString() {
public void attach( BuildContext context ) {
getLeftTupleSource().addTupleSink( this, context );
- if (context == null) {
- return;
- }
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ if ( ! context.getNodes().contains( this.getLeftTupleSource() ) ) {
getLeftTupleSource().updateSink( this, propagationContext, workingMemory );
}
}
diff --git a/drools-core/src/main/java/org/drools/reteoo/Rete.java b/drools-core/src/main/java/org/drools/reteoo/Rete.java
index f54ff67f969..a011fc3ee39 100644
--- a/drools-core/src/main/java/org/drools/reteoo/Rete.java
+++ b/drools-core/src/main/java/org/drools/reteoo/Rete.java
@@ -165,6 +165,10 @@ public void attach( BuildContext context ) {
throw new UnsupportedOperationException( "cannot call attach() from the root Rete node" );
}
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ // do nothing
+ }
+
public void networkUpdated(UpdateContext updateContext) {
// nothing to do
}
@@ -260,5 +264,9 @@ public void byPassModifyToBetaNode(InternalFactHandle factHandle,
@Override
public long calculateDeclaredMask(List settableProperties) {
throw new UnsupportedOperationException();
- }
+ }
+
+ public short getType() {
+ return -1;
+ }
}
diff --git a/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java b/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java
index 919cc6c3f89..7761009d902 100644
--- a/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java
+++ b/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java
@@ -245,7 +245,7 @@ public synchronized void removeRule(final Rule rule) {
final RuleRemovalContext context = new RuleRemovalContext( rule );
final BaseNode[] nodes = this.rules.remove( rule );
-
+ System.out.println( Thread.currentThread().getName() + " removing " + rule.getName() );
for (BaseNode node : nodes) {
NodeSet nodeSet = new NodeSet();
node.collectAncestors(nodeSet);
diff --git a/drools-core/src/main/java/org/drools/reteoo/RightInputAdapterNode.java b/drools-core/src/main/java/org/drools/reteoo/RightInputAdapterNode.java
index f99e3d1f2ce..90cc57c1c3e 100644
--- a/drools-core/src/main/java/org/drools/reteoo/RightInputAdapterNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/RightInputAdapterNode.java
@@ -225,16 +225,10 @@ public void modifyLeftTuple(LeftTuple leftTuple,
public void attach( BuildContext context ) {
this.tupleSource.addTupleSink( this, context );
- if (context == null) {
- return;
- }
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ if ( ! context.getNodes().contains( this.getLeftTupleSource() ) ) {
this.tupleSource.updateSink( this,
propagationContext,
workingMemory );
@@ -331,7 +325,7 @@ public void setPreviousLeftTupleSinkNode(final LeftTupleSinkNode previous) {
}
public short getType() {
- return NodeTypeEnums.RightInputAdaterNode;
+ return NodeTypeEnums.RightInputAdapterNode;
}
public int hashCode() {
@@ -420,7 +414,7 @@ public void readExternal(ObjectInput in) throws IOException,
}
public short getNodeType() {
- return NodeTypeEnums.RightInputAdaterNode;
+ return NodeTypeEnums.RightInputAdapterNode;
}
}
diff --git a/drools-core/src/main/java/org/drools/reteoo/RuleTerminalNode.java b/drools-core/src/main/java/org/drools/reteoo/RuleTerminalNode.java
index e1ef5d6560d..1589da92ec6 100644
--- a/drools-core/src/main/java/org/drools/reteoo/RuleTerminalNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/RuleTerminalNode.java
@@ -16,7 +16,6 @@
package org.drools.reteoo;
-import org.drools.RuleBaseConfiguration;
import org.drools.base.mvel.MVELEnabledExpression;
import org.drools.base.mvel.MVELSalienceExpression;
import org.drools.common.AgendaItem;
@@ -329,16 +328,10 @@ public String toString() {
public void attach( BuildContext context ) {
getLeftTupleSource().addTupleSink(this, context);
- if (context == null) {
- return;
- }
+ }
- for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
- final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null );
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ if ( ! context.getNodes().contains( this.getLeftTupleSource() ) ) {
getLeftTupleSource().updateSink(this, propagationContext, workingMemory);
}
}
diff --git a/drools-core/src/main/java/org/drools/reteoo/WindowNode.java b/drools-core/src/main/java/org/drools/reteoo/WindowNode.java
index 3c412bb75fc..d50cb7f3c2a 100644
--- a/drools-core/src/main/java/org/drools/reteoo/WindowNode.java
+++ b/drools-core/src/main/java/org/drools/reteoo/WindowNode.java
@@ -116,6 +116,10 @@ public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(entryPoint);
}
+ public short getType() {
+ return NodeTypeEnums.WindowNode;
+ }
+
/**
* Returns the FieldConstraints
*
@@ -135,23 +139,13 @@ public Behavior[] getBehaviors() {
public void attach(BuildContext context) {
this.source.addObjectSink(this);
- if (context == null) {
- return;
- }
+ }
- for (InternalWorkingMemory workingMemory : context.getWorkingMemories()) {
- final PropagationContext propagationContext = new PropagationContextImpl(
- workingMemory.getNextPropagationIdCounter(),
- PropagationContext.RULE_ADDITION,
- null,
- null,
- null);
- this.source.updateSink(this,
- propagationContext,
- workingMemory);
- }
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ // do nothing, this node's updateSink will be called from the beta network
}
+
public void assertObject(final InternalFactHandle factHandle,
final PropagationContext context,
final InternalWorkingMemory workingMemory) {
diff --git a/drools-core/src/main/java/org/drools/reteoo/builder/BuildContext.java b/drools-core/src/main/java/org/drools/reteoo/builder/BuildContext.java
index 94a9de2c27f..5da52d2ad13 100755
--- a/drools-core/src/main/java/org/drools/reteoo/builder/BuildContext.java
+++ b/drools-core/src/main/java/org/drools/reteoo/builder/BuildContext.java
@@ -396,11 +396,8 @@ public List getNodes() {
return nodes;
}
- /**
- * @param nodes the nodes to set
- */
- public void setNodes(List nodes) {
- this.nodes = nodes;
+ public void addNode(BaseNode node) {
+ nodes.add(node);
}
/**
diff --git a/drools-core/src/main/java/org/drools/reteoo/builder/BuildUtils.java b/drools-core/src/main/java/org/drools/reteoo/builder/BuildUtils.java
index b30dca388a1..c274ccb38fa 100755
--- a/drools-core/src/main/java/org/drools/reteoo/builder/BuildUtils.java
+++ b/drools-core/src/main/java/org/drools/reteoo/builder/BuildUtils.java
@@ -144,7 +144,7 @@ public BaseNode attachNode(final BuildContext context,
node.setPartitionId( partition );
node.attach(context);
// adds the node to the context list to track all added nodes
- context.getNodes().add( node );
+ context.addNode( node );
} else {
// shared node found
// undo previous id assignment
diff --git a/drools-core/src/main/java/org/drools/reteoo/builder/ConditionalBranchBuilder.java b/drools-core/src/main/java/org/drools/reteoo/builder/ConditionalBranchBuilder.java
index dbe8443a264..26a7e8c80ae 100644
--- a/drools-core/src/main/java/org/drools/reteoo/builder/ConditionalBranchBuilder.java
+++ b/drools-core/src/main/java/org/drools/reteoo/builder/ConditionalBranchBuilder.java
@@ -32,7 +32,7 @@ private ConditionalBranchEvaluator buildConditionalBranchEvaluator( BuildContext
RuleTerminalNode terminalNode = buildTerminalNodeForNamedConsequence(context, conditionalBranch.getNamedConsequence());
terminalNode.networkUpdated(new UpdateContext());
// adds the terminal node to the list of nodes created/added by this sub-rule
- context.getNodes().add(terminalNode);
+ context.addNode(terminalNode);
return new ConditionalBranchEvaluator( conditionalBranch.getEvalCondition(),
context.getTupleSource().getPartitionId(),
diff --git a/drools-core/src/main/java/org/drools/reteoo/builder/NamedConsequenceBuilder.java b/drools-core/src/main/java/org/drools/reteoo/builder/NamedConsequenceBuilder.java
index 52de969cf15..ef38beede9e 100644
--- a/drools-core/src/main/java/org/drools/reteoo/builder/NamedConsequenceBuilder.java
+++ b/drools-core/src/main/java/org/drools/reteoo/builder/NamedConsequenceBuilder.java
@@ -2,6 +2,8 @@
import org.drools.ActivationListenerFactory;
import org.drools.common.BaseNode;
+import org.drools.common.InternalWorkingMemory;
+import org.drools.common.PropagationContextImpl;
import org.drools.common.UpdateContext;
import org.drools.reteoo.RuleTerminalNode;
import org.drools.reteoo.TerminalNode;
@@ -9,6 +11,7 @@
import org.drools.rule.NamedConsequence;
import org.drools.rule.Rule;
import org.drools.rule.RuleConditionElement;
+import org.drools.spi.PropagationContext;
public class NamedConsequenceBuilder implements ReteooComponentBuilder {
@@ -21,7 +24,21 @@ public void build(BuildContext context, BuildUtils utils, RuleConditionElement r
terminalNode.networkUpdated(new UpdateContext());
// adds the terminal node to the list of nodes created/added by this sub-rule
- context.getNodes().add( terminalNode );
+ context.addNode(terminalNode);
+
+ for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
+ final PropagationContext propagationContext = new PropagationContextImpl(workingMemory.getNextPropagationIdCounter(),
+ PropagationContext.RULE_ADDITION,
+ null,
+ null,
+ null);
+
+ for ( BaseNode node : context.getNodes() ) {
+ node.updateSinkOnAttach( context, propagationContext, workingMemory );
+ }
+
+ propagationContext.evaluateActionQueue( workingMemory );
+ }
}
public boolean requiresLeftActivation(BuildUtils utils, RuleConditionElement rce) {
diff --git a/drools-core/src/main/java/org/drools/reteoo/builder/PatternBuilder.java b/drools-core/src/main/java/org/drools/reteoo/builder/PatternBuilder.java
index 0ac27dfe39e..cea8d4f8e31 100755
--- a/drools-core/src/main/java/org/drools/reteoo/builder/PatternBuilder.java
+++ b/drools-core/src/main/java/org/drools/reteoo/builder/PatternBuilder.java
@@ -34,7 +34,6 @@
import org.drools.reteoo.EntryPointNode;
import org.drools.reteoo.ObjectSource;
import org.drools.reteoo.ObjectTypeNode;
-import org.drools.reteoo.ReteooComponentFactory;
import org.drools.reteoo.PropagationQueuingNode;
import org.drools.reteoo.WindowNode;
import org.drools.rule.Behavior;
@@ -284,6 +283,10 @@ public static ObjectTypeNode attachObjectTypeNode(BuildContext context,
ruleBase.getRete(),
context );
epn.attach( context );
+ for ( InternalWorkingMemory wm : wms ) {
+ wm.updateEntryPointsCache();
+ epn.updateSinkOnAttach( context, wm );
+ }
}
ObjectTypeNode otn = new ObjectTypeNode( context.getNextId(),
@@ -296,6 +299,9 @@ public static ObjectTypeNode attachObjectTypeNode(BuildContext context,
otn.setExpirationOffset( expirationOffset );
otn.attach( context );
+ for ( InternalWorkingMemory wm : wms ) {
+ otn.updateSinkOnAttach( context, wm );
+ }
return otn;
} finally {
diff --git a/drools-core/src/main/java/org/drools/reteoo/builder/ReteooRuleBuilder.java b/drools-core/src/main/java/org/drools/reteoo/builder/ReteooRuleBuilder.java
index 892c6325ff8..087a8efe9f9 100755
--- a/drools-core/src/main/java/org/drools/reteoo/builder/ReteooRuleBuilder.java
+++ b/drools-core/src/main/java/org/drools/reteoo/builder/ReteooRuleBuilder.java
@@ -21,6 +21,8 @@
import org.drools.base.ClassObjectType;
import org.drools.common.BaseNode;
import org.drools.common.InternalRuleBase;
+import org.drools.common.InternalWorkingMemory;
+import org.drools.common.PropagationContextImpl;
import org.drools.common.UpdateContext;
import org.drools.conf.EventProcessingOption;
import org.drools.reteoo.ReteooBuilder;
@@ -42,6 +44,7 @@
import org.drools.rule.Rule;
import org.drools.rule.WindowDeclaration;
import org.drools.rule.WindowReference;
+import org.drools.spi.PropagationContext;
import org.drools.time.TemporalDependencyMatrix;
import java.util.ArrayList;
@@ -73,7 +76,7 @@ public ReteooRuleBuilder() {
this.utils.addBuilder( EntryPoint.class,
new EntryPointBuilder() );
this.utils.addBuilder( WindowReference.class,
- new WindowReferenceBuilder() );
+ new WindowReferenceBuilder() );
this.utils.addBuilder( NamedConsequence.class,
new NamedConsequenceBuilder() );
this.utils.addBuilder( ConditionalBranch.class,
@@ -169,18 +172,32 @@ private TerminalNode addSubRule( final BuildContext context,
context );
BaseNode baseTerminalNode = (BaseNode) terminal;
- baseTerminalNode.networkUpdated(new UpdateContext());
- baseTerminalNode.attach(context);
-
- // adds the terminal node to the list of nodes created/added by this sub-rule
- context.getNodes().add( baseTerminalNode );
+ baseTerminalNode.attach( context );
+ context.addNode( baseTerminalNode );
- // assigns partition IDs to the new nodes
- //assignPartitionId(context);
+ updatePropagations( baseTerminalNode, context );
return terminal;
}
+ private void updatePropagations( BaseNode baseTerminalNode, BuildContext context ) {
+ baseTerminalNode.networkUpdated( new UpdateContext() );
+
+ for ( InternalWorkingMemory workingMemory : context.getWorkingMemories() ) {
+ final PropagationContext propagationContext = new PropagationContextImpl(workingMemory.getNextPropagationIdCounter(),
+ PropagationContext.RULE_ADDITION,
+ null,
+ null,
+ null);
+
+ for ( BaseNode node : context.getNodes() ) {
+ node.updateSinkOnAttach( context, propagationContext, workingMemory );
+ }
+
+ propagationContext.evaluateActionQueue( workingMemory );
+ }
+ }
+
/**
* Adds a query pattern to the given subrule
*
diff --git a/drools-core/src/test/java/org/drools/reteoo/BaseNodeTest.java b/drools-core/src/test/java/org/drools/reteoo/BaseNodeTest.java
index d12b2b1f52a..e1db7bc20f8 100644
--- a/drools-core/src/test/java/org/drools/reteoo/BaseNodeTest.java
+++ b/drools-core/src/test/java/org/drools/reteoo/BaseNodeTest.java
@@ -59,6 +59,9 @@ public void attach( BuildContext context ) {
}
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ }
+
public void updateNewNode(final InternalWorkingMemory workingMemory,
final PropagationContext context) {
// TODO Auto-generated method stub
@@ -82,6 +85,9 @@ public void networkUpdated(UpdateContext updateContext) {
}
+ public short getType() {
+ return -1;
+ }
}
}
diff --git a/drools-core/src/test/java/org/drools/reteoo/MockLeftTupleSink.java b/drools-core/src/test/java/org/drools/reteoo/MockLeftTupleSink.java
index 55d3b6381d3..69f8ca9db76 100644
--- a/drools-core/src/test/java/org/drools/reteoo/MockLeftTupleSink.java
+++ b/drools-core/src/test/java/org/drools/reteoo/MockLeftTupleSink.java
@@ -103,6 +103,9 @@ public void attach(BuildContext buildContext) {
}
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ }
+
public List getPropagatedTuples(final ReteooWorkingMemory workingMemory,
final LeftTupleSink sink) {
// TODO Auto-generated method stub
diff --git a/drools-core/src/test/java/org/drools/reteoo/MockObjectSource.java b/drools-core/src/test/java/org/drools/reteoo/MockObjectSource.java
index 2f818df2ccf..a07f120a1a4 100644
--- a/drools-core/src/test/java/org/drools/reteoo/MockObjectSource.java
+++ b/drools-core/src/test/java/org/drools/reteoo/MockObjectSource.java
@@ -95,10 +95,16 @@ public void updateSink(final ObjectSink sink,
public void attach(BuildContext context) {
}
-
+
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ }
+
@Override
public long calculateDeclaredMask(List settableProperties) {
throw new UnsupportedOperationException();
- }
+ }
+ public short getType() {
+ return -1;
+ }
}
diff --git a/drools-core/src/test/java/org/drools/reteoo/MockTupleSource.java b/drools-core/src/test/java/org/drools/reteoo/MockTupleSource.java
index 68cd12132ec..cff35d4b1c6 100644
--- a/drools-core/src/test/java/org/drools/reteoo/MockTupleSource.java
+++ b/drools-core/src/test/java/org/drools/reteoo/MockTupleSource.java
@@ -64,6 +64,9 @@ public void attach( BuildContext context ) {
}
+ public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
+ }
+
@Override
public void networkUpdated(UpdateContext updateContext) {
// TODO Auto-generated method stub
@@ -74,4 +77,7 @@ protected ObjectTypeNode getObjectTypeNode() {
return null;
}
+ public short getType() {
+ return -1;
+ }
}
diff --git a/drools-core/src/test/java/org/drools/reteoo/ReteTest.java b/drools-core/src/test/java/org/drools/reteoo/ReteTest.java
index 0f00fc887bb..4676f554d0d 100644
--- a/drools-core/src/test/java/org/drools/reteoo/ReteTest.java
+++ b/drools-core/src/test/java/org/drools/reteoo/ReteTest.java
@@ -40,7 +40,6 @@
import org.drools.FactHandle;
import org.drools.spi.PropagationContext;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -247,6 +246,7 @@ public void testHierarchy() {
new ClassObjectType( List.class ),
buildContext );
listOtn.attach(buildContext);
+ //listOtn.updateSinkOnAttach(buildContext, true, true );
// Will automatically create an ArrayList ObjectTypeNode
FactHandle handle = workingMemory.insert( new ArrayList() );
@@ -296,7 +296,16 @@ public void testHierarchy() {
final MockObjectSink collectionSink = new MockObjectSink();
collectionOtn.addObjectSink( collectionSink );
- collectionOtn.attach( new TestBuildContext( new InternalWorkingMemory[]{workingMemory} ) );
+ final PropagationContext mockPropagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
+ PropagationContext.RULE_ADDITION,
+ null,
+ null,
+ null );
+
+
+ TestBuildContext testBuildContext = new TestBuildContext( new InternalWorkingMemory[]{workingMemory} );
+ collectionOtn.attach( testBuildContext );
+ collectionOtn.updateSinkOnAttach( testBuildContext, mockPropagationContext, workingMemory );
assertEquals( 1,
collectionSink.getAsserted().size() );