From fa39028c72f46a211f56cc6389a10ca3c3da3d96 Mon Sep 17 00:00:00 2001 From: Mario Fusco Date: Tue, 28 Feb 2017 14:03:15 +0100 Subject: [PATCH] [DROOLS-1445] add declarations required by accumulate functions into accumulate node left mask (#1120) --- .../integrationtests/AccumulateTest.java | 49 ++++++++++++------- .../PropertySpecificTest.java | 2 +- .../core/datasources/CursoredDataSource.java | 4 +- .../drools/core/metadata/ModifyLiteral.java | 2 +- .../core/reteoo/AbstractTerminalNode.java | 2 +- .../drools/core/reteoo/AccumulateNode.java | 29 +++++++++++ .../java/org/drools/core/reteoo/BetaNode.java | 8 +-- .../core/reteoo/LeftInputAdapterNode.java | 2 +- .../drools/core/reteoo/LeftTupleSource.java | 2 +- .../org/drools/core/reteoo/ObjectSource.java | 16 +++--- .../core/reteoo/PropertySpecificUtil.java | 2 +- 11 files changed, 79 insertions(+), 39 deletions(-) diff --git a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/AccumulateTest.java b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/AccumulateTest.java index c84b8252239..780fed8fb09 100644 --- a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/AccumulateTest.java +++ b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/AccumulateTest.java @@ -15,6 +15,24 @@ package org.drools.compiler.integrationtests; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Serializable; +import java.io.StringReader; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + import org.drools.compiler.Cheese; import org.drools.compiler.Cheesery; import org.drools.compiler.CommonTestMethodBase; @@ -55,30 +73,13 @@ import org.kie.internal.KnowledgeBaseFactory; import org.kie.internal.builder.KnowledgeBuilder; import org.kie.internal.builder.KnowledgeBuilderFactory; +import org.kie.internal.builder.conf.PropertySpecificOption; import org.kie.internal.io.ResourceFactory; import org.kie.internal.runtime.StatefulKnowledgeSession; import org.kie.internal.utils.KieHelper; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.io.Serializable; -import java.io.StringReader; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - import static org.hamcrest.CoreMatchers.is; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -2790,6 +2791,16 @@ public void testFromAccumulateWithoutSeparator() throws Exception { @Test public void testAccFunctionOpaqueJoins() throws Exception { // DROOLS-661 + testAccFunctionOpaqueJoins(PropertySpecificOption.ALLOWED); + } + + @Test + public void testAccFunctionOpaqueJoinsWithPropertyReactivity() throws Exception { + // DROOLS-1445 + testAccFunctionOpaqueJoins(PropertySpecificOption.ALWAYS); + } + + private void testAccFunctionOpaqueJoins(PropertySpecificOption propertySpecificOption) throws Exception { String str = "package org.test; " + "import java.util.*; " + "global List list; " + @@ -2845,7 +2856,7 @@ public void testAccFunctionOpaqueJoins() throws Exception { " list2.add( $tot ); " + "end "; - KieHelper helper = new KieHelper(); + KieHelper helper = new KieHelper( propertySpecificOption ); KieSession ks = helper.addContent( str, ResourceType.DRL ).build().newKieSession(); List list = new ArrayList(); ks.setGlobal( "list", list ); diff --git a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/PropertySpecificTest.java b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/PropertySpecificTest.java index 121dd490190..b1c4f585694 100644 --- a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/PropertySpecificTest.java +++ b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/PropertySpecificTest.java @@ -60,7 +60,7 @@ public static List getSettableProperties(InternalWorkingMemory workingMe } public static List getSettableProperties( InternalKnowledgeBase kBase, ObjectTypeNode objectTypeNode ) { - return PropertySpecificUtil.getSettableProperties( kBase, getNodeClass( objectTypeNode ) ); + return PropertySpecificUtil.getAccessibleProperties( kBase, getNodeClass( objectTypeNode ) ); } public static Class getNodeClass( ObjectTypeNode objectTypeNode ) { diff --git a/drools-core/src/main/java/org/drools/core/datasources/CursoredDataSource.java b/drools-core/src/main/java/org/drools/core/datasources/CursoredDataSource.java index 4a79c8376c0..891fe05583b 100644 --- a/drools-core/src/main/java/org/drools/core/datasources/CursoredDataSource.java +++ b/drools-core/src/main/java/org/drools/core/datasources/CursoredDataSource.java @@ -57,7 +57,7 @@ import static org.drools.core.common.DefaultFactHandle.determineIdentityHashCode; import static org.drools.core.reteoo.PropertySpecificUtil.allSetButTraitBitMask; import static org.drools.core.reteoo.PropertySpecificUtil.calculatePositiveMask; -import static org.drools.core.reteoo.PropertySpecificUtil.getSettableProperties; +import static org.drools.core.reteoo.PropertySpecificUtil.getAccessibleProperties; public class CursoredDataSource implements InternalDataSource { @@ -111,7 +111,7 @@ private FactHandle insertIntoWm( T object ) { public void update(FactHandle handle, T object, String... modifiedProperties) { BitMask mask = modifiedProperties == null || modifiedProperties.length == 0 ? allSetButTraitBitMask() : - calculatePositiveMask(asList(modifiedProperties), getSettableProperties(workingMemory.getKnowledgeBase(), object.getClass())); + calculatePositiveMask( asList(modifiedProperties), getAccessibleProperties( workingMemory.getKnowledgeBase(), object.getClass() ) ); internalUpdate((DataSourceFactHandle) handle, object, mask, Object.class, null); } diff --git a/drools-core/src/main/java/org/drools/core/metadata/ModifyLiteral.java b/drools-core/src/main/java/org/drools/core/metadata/ModifyLiteral.java index e2b42263697..2f9f2beaf99 100644 --- a/drools-core/src/main/java/org/drools/core/metadata/ModifyLiteral.java +++ b/drools-core/src/main/java/org/drools/core/metadata/ModifyLiteral.java @@ -142,7 +142,7 @@ protected void computeModificationMasks( InternalKnowledgeBase knowledgeBase ) { protected List getAccessibleProperties( Object o, InternalKnowledgeBase knowledgeBase ) { if ( knowledgeBase != null ) { - return PropertySpecificUtil.getSettableProperties( knowledgeBase, o.getClass() ); + return PropertySpecificUtil.getAccessibleProperties( knowledgeBase, o.getClass() ); } else { return ClassUtils.getAccessibleProperties( o.getClass() ); } diff --git a/drools-core/src/main/java/org/drools/core/reteoo/AbstractTerminalNode.java b/drools-core/src/main/java/org/drools/core/reteoo/AbstractTerminalNode.java index b92c6246e80..7261b77c4dd 100644 --- a/drools-core/src/main/java/org/drools/core/reteoo/AbstractTerminalNode.java +++ b/drools-core/src/main/java/org/drools/core/reteoo/AbstractTerminalNode.java @@ -116,7 +116,7 @@ public void initDeclaredMask(BuildContext context) { // if property specific is not on, then accept all modification propagations setDeclaredMask( AllSetBitMask.get() ); } else { - List settableProperties = getSettableProperties(context.getKnowledgeBase(), objectClass); + List settableProperties = getAccessibleProperties( context.getKnowledgeBase(), objectClass ); setDeclaredMask( calculatePositiveMask(pattern.getListenedProperties(), settableProperties) ); setNegativeMask( calculateNegativeMask(pattern.getListenedProperties(), settableProperties) ); } diff --git a/drools-core/src/main/java/org/drools/core/reteoo/AccumulateNode.java b/drools-core/src/main/java/org/drools/core/reteoo/AccumulateNode.java index f6553cb9527..c54fbe95dc5 100644 --- a/drools-core/src/main/java/org/drools/core/reteoo/AccumulateNode.java +++ b/drools-core/src/main/java/org/drools/core/reteoo/AccumulateNode.java @@ -21,14 +21,17 @@ import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Arrays; +import java.util.List; import java.util.Map; import org.drools.core.RuleBaseConfiguration; +import org.drools.core.base.ClassObjectType; import org.drools.core.common.BetaConstraints; import org.drools.core.common.InternalFactHandle; import org.drools.core.common.InternalWorkingMemory; import org.drools.core.common.Memory; import org.drools.core.common.WorkingMemoryAction; +import org.drools.core.impl.InternalKnowledgeBase; import org.drools.core.marshalling.impl.PersisterHelper; import org.drools.core.marshalling.impl.ProtobufInputMarshaller; import org.drools.core.marshalling.impl.ProtobufInputMarshaller.TupleKey; @@ -37,10 +40,16 @@ import org.drools.core.reteoo.builder.BuildContext; import org.drools.core.rule.Accumulate; import org.drools.core.rule.ContextEntry; +import org.drools.core.rule.Declaration; +import org.drools.core.rule.TypeDeclaration; import org.drools.core.spi.Accumulator; import org.drools.core.spi.AlphaNodeFieldConstraint; +import org.drools.core.spi.ObjectType; import org.drools.core.spi.PropagationContext; import org.drools.core.util.AbstractBaseLinkedListNode; +import org.drools.core.util.bitmask.BitMask; + +import static org.drools.core.reteoo.PropertySpecificUtil.calculatePositiveMask; /** * AccumulateNode @@ -82,11 +91,31 @@ public AccumulateNode(final int id, this.unwrapRightObject = unwrapRightObject; this.tupleMemoryEnabled = context.isTupleMemoryEnabled(); + addAccFunctionDeclarationsToLeftMask( context.getKnowledgeBase(), leftInput, accumulate ); + hashcode = this.leftInput.hashCode() ^ this.rightInput.hashCode() ^ this.accumulate.hashCode() ^ this.resultBinder.hashCode() ^ Arrays.hashCode( this.resultConstraints ); + + } + + private void addAccFunctionDeclarationsToLeftMask( InternalKnowledgeBase kbase, LeftTupleSource leftInput, Accumulate accumulate ) { + BitMask leftMask = getLeftInferredMask(); + ObjectType leftObjectType = leftInput.getObjectType(); + if (leftObjectType instanceof ClassObjectType ) { + TypeDeclaration typeDeclaration = kbase.getExactTypeDeclaration( ((ClassObjectType) leftObjectType).getClassType() ); + if (typeDeclaration != null && typeDeclaration.isPropertyReactive()) { + List accessibleProperties = typeDeclaration.getAccessibleProperties(); + for ( Declaration decl : accumulate.getRequiredDeclarations() ) { + if ( leftObjectType.equals( decl.getPattern().getObjectType() ) ) { + leftMask = leftMask.setAll( calculatePositiveMask( decl.getPattern().getListenedProperties(), accessibleProperties ) ); + } + } + } + } + setLeftInferredMask( leftMask ); } public void readExternal( ObjectInput in ) throws IOException, diff --git a/drools-core/src/main/java/org/drools/core/reteoo/BetaNode.java b/drools-core/src/main/java/org/drools/core/reteoo/BetaNode.java index abf6281f2e0..fb503a43113 100644 --- a/drools-core/src/main/java/org/drools/core/reteoo/BetaNode.java +++ b/drools-core/src/main/java/org/drools/core/reteoo/BetaNode.java @@ -169,10 +169,10 @@ protected void initDeclaredMask(BuildContext context, Class objectClass = ((ClassObjectType) objectType).getClassType(); if (isPropertyReactive(context, objectClass)) { rightListenedProperties = pattern.getListenedProperties(); - List settableProperties = getSettableProperties(context.getKnowledgeBase(), objectClass); - rightDeclaredMask = calculatePositiveMask(rightListenedProperties, settableProperties); - rightDeclaredMask = rightDeclaredMask.setAll(constraints.getListenedPropertyMask(settableProperties)); - rightNegativeMask = calculateNegativeMask(rightListenedProperties, settableProperties); + List accessibleProperties = getAccessibleProperties( context.getKnowledgeBase(), objectClass ); + rightDeclaredMask = calculatePositiveMask(rightListenedProperties, accessibleProperties); + rightDeclaredMask = rightDeclaredMask.setAll(constraints.getListenedPropertyMask(accessibleProperties)); + rightNegativeMask = calculateNegativeMask(rightListenedProperties, accessibleProperties); } else { // if property reactive is not on, then accept all modification propagations rightDeclaredMask = AllSetBitMask.get(); diff --git a/drools-core/src/main/java/org/drools/core/reteoo/LeftInputAdapterNode.java b/drools-core/src/main/java/org/drools/core/reteoo/LeftInputAdapterNode.java index 6b3bc675fa0..b9058172cf9 100644 --- a/drools-core/src/main/java/org/drools/core/reteoo/LeftInputAdapterNode.java +++ b/drools-core/src/main/java/org/drools/core/reteoo/LeftInputAdapterNode.java @@ -115,7 +115,7 @@ private BitMask calculateSinkMask(BuildContext context) { Class objectClass = ((ClassWireable) objectType).getClassType(); return isPropertyReactive( context, objectClass ) ? calculatePositiveMask( pattern.getListenedProperties(), - getSettableProperties( context.getKnowledgeBase(), objectClass ) ) : + getAccessibleProperties( context.getKnowledgeBase(), objectClass ) ) : AllSetBitMask.get(); } diff --git a/drools-core/src/main/java/org/drools/core/reteoo/LeftTupleSource.java b/drools-core/src/main/java/org/drools/core/reteoo/LeftTupleSource.java index 66ea0413980..8e4897fba17 100644 --- a/drools-core/src/main/java/org/drools/core/reteoo/LeftTupleSource.java +++ b/drools-core/src/main/java/org/drools/core/reteoo/LeftTupleSource.java @@ -254,7 +254,7 @@ protected void initDeclaredMask(BuildContext context, // TODO: at the moment if pattern is null (e.g. for eval node) we cannot calculate the mask, so we leave it to 0 if ( pattern != null ) { Collection leftListenedProperties = pattern.getListenedProperties(); - List settableProperties = getSettableProperties( context.getKnowledgeBase(), objectClass ); + List settableProperties = getAccessibleProperties( context.getKnowledgeBase(), objectClass ); leftDeclaredMask = calculatePositiveMask( leftListenedProperties, settableProperties ); leftNegativeMask = calculateNegativeMask( leftListenedProperties, settableProperties ); setLeftListenedProperties(leftListenedProperties); diff --git a/drools-core/src/main/java/org/drools/core/reteoo/ObjectSource.java b/drools-core/src/main/java/org/drools/core/reteoo/ObjectSource.java index cdd2e4238c2..529b69820c8 100644 --- a/drools-core/src/main/java/org/drools/core/reteoo/ObjectSource.java +++ b/drools-core/src/main/java/org/drools/core/reteoo/ObjectSource.java @@ -16,6 +16,12 @@ package org.drools.core.reteoo; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.List; + import org.drools.core.base.ClassObjectType; import org.drools.core.common.BaseNode; import org.drools.core.common.DefaultFactHandle; @@ -32,13 +38,7 @@ import org.drools.core.util.bitmask.BitMask; import org.drools.core.util.bitmask.EmptyBitMask; -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.util.List; - -import static org.drools.core.reteoo.PropertySpecificUtil.getSettableProperties; +import static org.drools.core.reteoo.PropertySpecificUtil.getAccessibleProperties; /** * A source of FactHandles for an ObjectSink. @@ -152,7 +152,7 @@ public void initDeclaredMask(BuildContext context) { // if property specific is not on, then accept all modification propagations declaredMask = AllSetBitMask.get(); } else { - List settableProperties = getSettableProperties(context.getKnowledgeBase(), objectClass); + List settableProperties = getAccessibleProperties( context.getKnowledgeBase(), objectClass ); declaredMask = calculateDeclaredMask(settableProperties); } } diff --git a/drools-core/src/main/java/org/drools/core/reteoo/PropertySpecificUtil.java b/drools-core/src/main/java/org/drools/core/reteoo/PropertySpecificUtil.java index 9bf7f37e971..48dc8d5c51d 100644 --- a/drools-core/src/main/java/org/drools/core/reteoo/PropertySpecificUtil.java +++ b/drools-core/src/main/java/org/drools/core/reteoo/PropertySpecificUtil.java @@ -111,7 +111,7 @@ public static boolean isPropertySetOnMask(BitMask mask, int index) { return mask.isSet(index + CUSTOM_BITS_OFFSET); } - public static List getSettableProperties(InternalKnowledgeBase kBase, Class nodeClass) { + public static List getAccessibleProperties( InternalKnowledgeBase kBase, Class nodeClass ) { return kBase.getOrCreateExactTypeDeclaration(nodeClass).getAccessibleProperties(); } }