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() );