[jboss-svn-commits] JBL Code SVN: r7724 - in labs/jbossrules/trunk: drools-compiler/src/main/java/org/drools/semantics/java drools-core/src/main/java/org/drools/reteoo drools-core/src/test/java/org/drools/reteoo

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Mon Nov 20 11:22:10 EST 2006


Author: tirelli
Date: 2006-11-20 11:21:55 -0500 (Mon, 20 Nov 2006)
New Revision: 7724

Added:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ExistsNode.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/ExistsNodeTest.java
Modified:
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/NotNode.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/QueryTerminalNode.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java
Log:
JBRULES-547: added specialized ExistsNode. Added unit test. All integration tests are green.

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java	2006-11-20 13:47:52 UTC (rev 7723)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java	2006-11-20 16:21:55 UTC (rev 7724)
@@ -289,7 +289,8 @@
 
                     this.innerDeclarations = null;
                 } else if ( object.getClass() == ExistsDescr.class ) {
-                    // We cannot have declarations created inside a not visible outside it, so track no declarations so they can be removed
+                    // We cannot have declarations created inside exists visible outside it, 
+                    // so track declarations in a way they can be removed
                     this.innerDeclarations = new HashMap();
                     final Exists exists = new Exists();
                     build( this.rule,

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ExistsNode.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ExistsNode.java	2006-11-20 13:47:52 UTC (rev 7723)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ExistsNode.java	2006-11-20 16:21:55 UTC (rev 7724)
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2006 JBoss Inc
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.drools.reteoo;
+
+import org.drools.common.BetaConstraints;
+import org.drools.common.EmptyBetaConstraints;
+import org.drools.common.InternalFactHandle;
+import org.drools.common.InternalWorkingMemory;
+import org.drools.spi.PropagationContext;
+import org.drools.util.Iterator;
+import org.drools.util.AbstractHashTable.FactEntry;
+
+/**
+ * <code>ExistsNode</code> extends <code>BetaNode</code> to perform tests for
+ * the existence of a Fact plus one or more conditions. Where existence
+ * is found the left ReteTuple is copied and propagated. Further to this it
+ * maintains the "truth" by cancelling any
+ * <code>Activation<code>s that are no longer 
+ * considered true by the retraction of ReteTuple's or FactHandleImpl.  
+ * Tuples are considered to be asserted from the left input and facts from the right input.
+ * The <code>BetaNode</code> provides the BetaMemory to store assserted ReteTuples and 
+ * <code>FactHandleImpl<code>s. Each fact handle is stored in the right 
+ * memory.
+ * 
+ * @author <a href="mailto:etirelli at redhat.com">Edson Tirelli</a>
+ *
+ */
+public class ExistsNode extends BetaNode {
+
+    private static final long serialVersionUID = 2597133625232012026L;
+
+    static int                notAssertObject  = 0;
+    static int                notAssertTuple   = 0;
+
+    // ------------------------------------------------------------
+    // Instance methods
+    // ------------------------------------------------------------
+
+    /**
+     * Constructs a new Exists node with EmptyBetaConstraints.
+     * 
+     * @paran id
+     *            The unique id for this node.
+     * @param leftInput
+     *            The left input <code>TupleSource</code>.
+     * @param rightInput
+     *            The right input <code>ObjectSource</code>.
+     */
+    ExistsNode(final int id,
+               final TupleSource leftInput,
+               final ObjectSource rightInput) {
+        super( id,
+               leftInput,
+               rightInput,
+               EmptyBetaConstraints.getInstance() );
+    }
+
+    /**
+     * Construct.
+     * 
+     * @paran id
+     *            The unique id for this node.
+     * @param leftInput
+     *            The left input <code>TupleSource</code>.
+     * @param rightInput
+     *            The right input <code>ObjectSource</code>.
+     * @param joinNodeBinder
+     *            The constraints to be aplied to the right objects
+     */
+    ExistsNode(final int id,
+            final TupleSource leftInput,
+            final ObjectSource rightInput,
+            final BetaConstraints joinNodeBinder) {
+        super( id,
+               leftInput,
+               rightInput,
+               joinNodeBinder );
+    }
+
+    /**
+     * Assert a new <code>ReteTuple</code> from the left input. It iterates
+     * over the right <code>FactHandleImpl</code>'s and if any match is found,
+     * a copy of the <code>ReteTuple</code> is made and propagated.
+     * 
+     * @param tuple
+     *            The <code>Tuple</code> being asserted.
+     * @param context
+     *            The <code>PropagationContext</code>
+     * @param workingMemory
+     *            The working memory seesion.
+     */
+    public void assertTuple(final ReteTuple leftTuple,
+                            final PropagationContext context,
+                            final InternalWorkingMemory workingMemory) {
+        final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory( this );
+        memory.getTupleMemory().add( leftTuple );
+
+        final Iterator it = memory.getFactHandleMemory().iterator( leftTuple );
+        this.constraints.updateFromTuple( workingMemory,
+                                          leftTuple );
+        int matches = 0;
+        for ( FactEntry entry = (FactEntry) it.next(); entry != null; entry = (FactEntry) it.next() ) {
+            final InternalFactHandle handle = entry.getFactHandle();
+            if ( this.constraints.isAllowedCachedLeft( handle.getObject() ) ) {
+                matches++;
+            }
+        }
+
+        leftTuple.setMatches( matches );
+
+        if ( matches > 0 ) {
+            this.sink.propagateAssertTuple( leftTuple,
+                                            context,
+                                            workingMemory );
+        }
+    }
+
+    /**
+     * Assert a new <code>FactHandleImpl</code> from the right input. If it
+     * matches any left ReteTuple's that had no matches before, propagate 
+     * tuple as an assertion.
+     * 
+     * @param handle
+     *            The <code>FactHandleImpl</code> being asserted.
+     * @param context
+     *            The <code>PropagationContext</code>
+     * @param workingMemory
+     *            The working memory seesion.
+     */
+    public void assertObject(final InternalFactHandle handle,
+                             final PropagationContext context,
+                             final InternalWorkingMemory workingMemory) {
+        final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory( this );
+        memory.getFactHandleMemory().add( handle );
+
+        final Iterator it = memory.getTupleMemory().iterator( handle );
+        this.constraints.updateFromFactHandle( workingMemory,
+                                               handle );
+        for ( ReteTuple tuple = (ReteTuple) it.next(); tuple != null; tuple = (ReteTuple) it.next() ) {
+            if ( this.constraints.isAllowedCachedRight( tuple ) ) {
+                final int matches = tuple.getMatches();
+                tuple.setMatches( matches + 1 );
+
+                // if this is the first match, propagate tuple
+                if( tuple.getMatches() == 1 ) {
+                    this.sink.propagateAssertTuple( tuple,
+                                                     context,
+                                                     workingMemory );
+                }
+            }
+        }
+    }
+
+    /**
+     * Retract the <code>FactHandleImpl</code>. If the handle has any
+     * <code>ReteTuple</code> matches and those tuples now have no
+     * other match, retract tuple
+     * 
+     * @param handle
+     *            the <codeFactHandleImpl</code> being retracted
+     * @param context
+     *            The <code>PropagationContext</code>
+     * @param workingMemory
+     *            The working memory seesion.
+     */
+    public void retractObject(final InternalFactHandle handle,
+                              final PropagationContext context,
+                              final InternalWorkingMemory workingMemory) {
+        final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory( this );
+        if ( !memory.getFactHandleMemory().remove( handle ) ) {
+            return;
+        }
+
+        final Iterator it = memory.getTupleMemory().iterator( handle );
+        this.constraints.updateFromFactHandle( workingMemory,
+                                               handle );
+        for ( ReteTuple tuple = (ReteTuple) it.next(); tuple != null; tuple = (ReteTuple) it.next() ) {
+            if ( this.constraints.isAllowedCachedRight( tuple ) ) {
+                tuple.setMatches( tuple.getMatches() - 1 );
+                if ( tuple.getMatches() == 0 ) {
+                    this.sink.propagateRetractTuple( tuple,
+                                                    context,
+                                                    workingMemory );
+                }
+            }
+        }
+    }
+
+    /**
+     * Retract the
+     * <code>ReteTuple<code>, any resulting propagated joins are also retracted. 
+     * 
+     * @param leftTuple
+     *            The tuple being retracted
+     * @param context
+     *            The <code>PropagationContext</code>
+     * @param workingMemory
+     *            The working memory seesion.
+     */
+    public void retractTuple(final ReteTuple leftTuple,
+                             final PropagationContext context,
+                             final InternalWorkingMemory workingMemory) {
+        final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory( this );
+
+        // Must use the tuple in memory as it has the tuple matches count
+        final ReteTuple tuple = (ReteTuple) memory.getTupleMemory().remove( leftTuple );
+        if ( tuple == null ) {
+            return;
+        }
+
+        if ( tuple.getMatches() > 0 ) {
+            this.sink.propagateRetractTuple( tuple,
+                                             context,
+                                             workingMemory );
+        }
+    }
+
+    /**
+     * Updates the given sink propagating all previously propagated tuples to it
+     * 
+     */
+    public void updateSink(final TupleSink sink,
+                           final PropagationContext context,
+                           final InternalWorkingMemory workingMemory) {
+        final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory( this );
+
+        final Iterator tupleIter = memory.getTupleMemory().iterator();
+        for ( ReteTuple tuple = (ReteTuple) tupleIter.next(); tuple != null; tuple = (ReteTuple) tupleIter.next() ) {
+            if ( tuple.getMatches() > 0 ) {
+                sink.assertTuple( new ReteTuple( tuple ),
+                                  context,
+                                  workingMemory );
+            }
+        }
+    }
+
+    public String toString() {
+        ObjectSource source = this.rightInput;
+        while ( source.getClass() != ObjectTypeNode.class ) {
+            source = source.objectSource;
+        }
+
+        return "[ExistsNode - " + ((ObjectTypeNode) source).getObjectType() + "]";
+    }
+
+}


Property changes on: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ExistsNode.java
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:keywords
   + id author date revision
Name: svn:eol-style
   + native

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/NotNode.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/NotNode.java	2006-11-20 13:47:52 UTC (rev 7723)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/NotNode.java	2006-11-20 16:21:55 UTC (rev 7724)
@@ -42,9 +42,7 @@
  *
  */
 public class NotNode extends BetaNode {
-    /**
-     * 
-     */
+
     private static final long serialVersionUID = 320L;
     static int                notAssertObject  = 0;
     static int                notAssertTuple   = 0;
@@ -229,22 +227,16 @@
     public void updateSink(final TupleSink sink,
                            final PropagationContext context,
                            final InternalWorkingMemory workingMemory) {
-        //        this.attachingNewNode = true;
-        //
-        //        final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory( this );
-        //        for ( final Iterator it = memory.getLeftTupleMemory().iterator(); it.hasNext(); ) {
-        //            final ReteTuple leftTuple = (ReteTuple) it.next();
-        //            if ( leftTuple.matchesSize() == 0 ) {
-        //                final ReteTuple child = new ReteTuple( leftTuple );
-        //                // no TupleMatch so instead add as a linked tuple
-        //                leftTuple.addLinkedTuple( new LinkedListObjectWrapper( child ) );
-        //                ((TupleSink) getTupleSinks().get( getTupleSinks().size() - 1 )).assertTuple( child,
-        //                                                                                             context,
-        //                                                                                             workingMemory );
-        //            }
-        //        }
-        //
-        //        this.attachingNewNode = true;
+        final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory( this );
+
+        final Iterator tupleIter = memory.getTupleMemory().iterator();
+        for ( ReteTuple tuple = (ReteTuple) tupleIter.next(); tuple != null; tuple = (ReteTuple) tupleIter.next() ) {
+            if ( tuple.getMatches() == 0 ) {
+                sink.assertTuple( new ReteTuple( tuple ),
+                                  context,
+                                  workingMemory );
+            }
+        }
     }
 
     public String toString() {

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/QueryTerminalNode.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/QueryTerminalNode.java	2006-11-20 13:47:52 UTC (rev 7723)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/QueryTerminalNode.java	2006-11-20 16:21:55 UTC (rev 7724)
@@ -111,9 +111,6 @@
     public void retractTuple(final ReteTuple tuple,
                              final PropagationContext context,
                              final InternalWorkingMemory workingMemory) {
-        // following code is needed because of queries that eventually uses "exists" 
-        final LinkedList list = (LinkedList) workingMemory.getNodeMemory( this );
-        list.remove( tuple );
     }
 
     public String toString() {

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java	2006-11-20 13:47:52 UTC (rev 7723)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java	2006-11-20 16:21:55 UTC (rev 7724)
@@ -38,7 +38,6 @@
 import org.drools.common.DefaultBetaConstraints;
 import org.drools.common.DoubleBetaConstraints;
 import org.drools.common.EmptyBetaConstraints;
-import org.drools.common.InstanceEqualsConstraint;
 import org.drools.common.InstanceNotEqualsConstraint;
 import org.drools.common.QuadroupleBetaConstraints;
 import org.drools.common.SingleBetaConstraints;
@@ -479,28 +478,7 @@
                                                                    tupleSource,
                                                                    ObjectSource,
                                                                    binder ) );
-        if ( not.getChild() instanceof Not ) {
-
-            final RightInputAdapterNode adapter = (RightInputAdapterNode) attachNode( new RightInputAdapterNode( this.id++,
-                                                                                                                 column,
-                                                                                                                 notNode ) );
-            attachNot( tupleSource,
-                       (Not) not.getChild(),
-                       adapter,
-                       EmptyBetaConstraints.getInstance(),
-                       column );
-        } else if ( not.getChild() instanceof Exists ) {
-            final RightInputAdapterNode adapter = (RightInputAdapterNode) attachNode( new RightInputAdapterNode( this.id++,
-                                                                                                                 column,
-                                                                                                                 notNode ) );
-            attachExists( tupleSource,
-                          (Exists) not.getChild(),
-                          adapter,
-                          EmptyBetaConstraints.getInstance(),
-                          column );
-        } else {
-            this.tupleSource = notNode;
-        }
+        this.tupleSource = notNode;
     }
 
     private void attachExists(final TupleSource tupleSource,
@@ -508,41 +486,11 @@
                               final ObjectSource ObjectSource,
                               final BetaConstraints binder,
                               final Column column) {
-        NotNode notNode = (NotNode) attachNode( new NotNode( this.id++,
+        ExistsNode existsNode = (ExistsNode) attachNode( new ExistsNode( this.id++,
                                                              tupleSource,
                                                              ObjectSource,
                                                              binder ) );
-        RightInputAdapterNode adapter = (RightInputAdapterNode) attachNode( new RightInputAdapterNode( this.id++,
-                                                                                                       column,
-                                                                                                       notNode ) );
-
-        final BetaConstraints identityBinder = new SingleBetaConstraints( new InstanceEqualsConstraint( column ), this.ruleBase.getConfiguration() );
-        notNode = (NotNode) attachNode( new NotNode( this.id++,
-                                                     tupleSource,
-                                                     adapter,
-                                                     identityBinder ) );
-
-        if ( exists.getChild() instanceof Not ) {
-            adapter = (RightInputAdapterNode) attachNode( new RightInputAdapterNode( this.id++,
-                                                                                     column,
-                                                                                     notNode ) );
-            attachNot( tupleSource,
-                       (Not) exists.getChild(),
-                       adapter,
-                       EmptyBetaConstraints.getInstance(),
-                       column );
-        } else if ( exists.getChild() instanceof Exists ) {
-            adapter = (RightInputAdapterNode) attachNode( new RightInputAdapterNode( this.id++,
-                                                                                     column,
-                                                                                     notNode ) );
-            attachExists( tupleSource,
-                          (Exists) exists.getChild(),
-                          adapter,
-                          EmptyBetaConstraints.getInstance(),
-                          column );
-        } else {
-            this.tupleSource = notNode;
-        }
+        this.tupleSource = existsNode;
     }
 
     /**

Added: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/ExistsNodeTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/ExistsNodeTest.java	2006-11-20 13:47:52 UTC (rev 7723)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/ExistsNodeTest.java	2006-11-20 16:21:55 UTC (rev 7724)
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2006 JBoss Inc
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.drools.reteoo;
+
+import java.beans.IntrospectionException;
+
+import junit.framework.Assert;
+
+import org.drools.Cheese;
+import org.drools.DroolsTestCase;
+import org.drools.FactException;
+import org.drools.RuleBaseConfiguration;
+import org.drools.RuleBaseFactory;
+import org.drools.common.DefaultBetaConstraints;
+import org.drools.common.DefaultFactHandle;
+import org.drools.common.PropagationContextImpl;
+import org.drools.rule.Rule;
+import org.drools.spi.BetaNodeFieldConstraint;
+import org.drools.spi.MockConstraint;
+import org.drools.spi.PropagationContext;
+
+/**
+ * @author etirelli
+ *
+ */
+public class ExistsNodeTest extends DroolsTestCase {
+    Rule                  rule;
+    PropagationContext    context;
+    ReteooWorkingMemory   workingMemory;
+    MockObjectSource      objectSource;
+    MockTupleSource       tupleSource;
+    MockTupleSink         sink;
+    ExistsNode            node;
+    RightInputAdapterNode ria;
+    BetaMemory            memory;
+    MockConstraint        constraint = new MockConstraint();
+
+    /**
+     * Setup the BetaNode used in each of the tests
+     * @throws IntrospectionException 
+     */
+    public void setUp() throws IntrospectionException {
+        this.rule = new Rule( "test-rule" );
+        this.context = new PropagationContextImpl( 0,
+                                                   PropagationContext.ASSERTION,
+                                                   null,
+                                                   null );
+        this.workingMemory = new ReteooWorkingMemory( 1,
+                                                      (ReteooRuleBase) RuleBaseFactory.newRuleBase() );
+
+        RuleBaseConfiguration configuration = new RuleBaseConfiguration();
+        
+        // string1Declaration is bound to column 3 
+        this.node = new ExistsNode( 15,
+                                 new MockTupleSource( 5 ),
+                                 new MockObjectSource( 8 ),
+                                 new DefaultBetaConstraints( new BetaNodeFieldConstraint[] { this.constraint }, configuration ) );
+
+        this.sink = new MockTupleSink();
+        this.node.addTupleSink( this.sink );
+
+        this.memory = (BetaMemory) this.workingMemory.getNodeMemory( this.node );
+    }
+
+    /**
+     * Test assertion with both Objects and Tuples
+     * 
+     * @throws AssertionException
+     */
+    public void testExistsStandard() throws FactException {
+        // assert tuple
+        final Cheese cheddar = new Cheese( "cheddar",
+                                           10 );
+        final DefaultFactHandle f0 = (DefaultFactHandle) this.workingMemory.assertObject( cheddar );
+
+        final ReteTuple tuple1 = new ReteTuple( f0 );
+
+        this.node.assertTuple( tuple1,
+                               this.context,
+                               this.workingMemory );
+
+        // no matching objects, so should not propagate
+        assertLength( 0,
+                      this.sink.getAsserted() );
+
+        assertLength( 0,
+                      this.sink.getRetracted() );
+
+        // assert will match, so should propagate
+        final Cheese brie = new Cheese( "brie",
+                                        10 );
+        final DefaultFactHandle f1 = (DefaultFactHandle) this.workingMemory.assertObject( brie );
+
+        this.node.assertObject( f1,
+                                this.context,
+                                this.workingMemory );
+
+        // check a single assertion
+        assertLength( 1,
+                      this.sink.getAsserted() );
+
+        assertLength( 0,
+                      this.sink.getRetracted() );
+
+        assertEquals( new ReteTuple( f0 ),
+                      ((Object[]) this.sink.getAsserted().get( 0 ))[0] );
+
+
+        // assert tuple, will have matches, so propagate
+        final DefaultFactHandle f2 = (DefaultFactHandle) this.workingMemory.assertObject( new Cheese( "gouda",
+                                                                                                      10 ) );
+        final ReteTuple tuple2 = new ReteTuple( f2 );
+        this.node.assertTuple( tuple2,
+                               this.context,
+                               this.workingMemory );
+
+        // check propagations 
+        assertLength( 2,
+                      this.sink.getAsserted() );
+
+        assertLength( 0,
+                      this.sink.getRetracted() );
+
+        // check memory sizes
+        assertEquals( 2,
+                      this.memory.getTupleMemory().size() );
+        assertEquals( 1,
+                      this.memory.getFactHandleMemory().size() );
+
+        // When this is retracter both tuples should be retracted
+        this.node.retractObject( f1,
+                                 this.context,
+                                 this.workingMemory );
+
+        // check retracts 
+        assertLength( 2,
+                      this.sink.getAsserted() );
+
+        assertLength( 2,
+                      this.sink.getRetracted() );
+    }
+
+    /**
+     * Test assertion with both Objects and Tuples
+     * 
+     * @throws AssertionException
+     */
+    public void testExistsWithConstraints() throws FactException {
+        this.constraint.isAllowed = false;
+
+        // assert tuple
+        final Cheese cheddar = new Cheese( "cheddar",
+                                           10 );
+        final DefaultFactHandle f0 = (DefaultFactHandle) this.workingMemory.assertObject( cheddar );
+
+        final ReteTuple tuple1 = new ReteTuple( f0 );
+
+        this.node.assertTuple( tuple1,
+                               this.context,
+                               this.workingMemory );
+
+        // no matching objects, so don't propagate
+        assertLength( 0,
+                      this.sink.getAsserted() );
+
+        assertLength( 0,
+                      this.sink.getRetracted() );
+
+        // assert will not match, so activation should stay propagated
+        final Cheese brie = new Cheese( "brie",
+                                        10 );
+        final DefaultFactHandle f1 = (DefaultFactHandle) this.workingMemory.assertObject( brie );
+
+        this.node.assertObject( f1,
+                                this.context,
+                                this.workingMemory );
+
+        // no matches, so no propagations still
+        assertLength( 0,
+                      this.sink.getAsserted() );
+
+        assertLength( 0,
+                      this.sink.getRetracted() );
+
+        // assert tuple, will have matches, so do assert propagation
+        final DefaultFactHandle f2 = (DefaultFactHandle) this.workingMemory.assertObject( new Cheese( "gouda",
+                                                                                                      10 ) );
+        final ReteTuple tuple2 = new ReteTuple( f2 );
+        this.node.assertTuple( tuple2,
+                               this.context,
+                               this.workingMemory );
+
+        assertLength( 0,
+                      this.sink.getAsserted() );
+
+        assertLength( 0,
+                      this.sink.getRetracted() );
+    }
+
+    /**
+     * Tests memory consistency after assert/modify/retract calls
+     * 
+     * @throws AssertionException
+     */
+    public void testExistsMemoryManagement() throws FactException {
+        try {
+            // assert tuple
+            final Cheese cheddar = new Cheese( "cheddar",
+                                               10 );
+            final DefaultFactHandle f0 = (DefaultFactHandle) this.workingMemory.assertObject( cheddar );
+            final ReteTuple tuple1 = new ReteTuple( f0 );
+
+            this.node.assertTuple( tuple1,
+                                   this.context,
+                                   this.workingMemory );
+
+            // assert will match, so should propagate
+            final Cheese brie = new Cheese( "brie",
+                                            10 );
+            final DefaultFactHandle f1 = (DefaultFactHandle) this.workingMemory.assertObject( brie );
+
+            // Initially, no objects in right memory
+            assertEquals( 0,
+                          this.memory.getFactHandleMemory().size() );
+            this.node.assertObject( f1,
+                                    this.context,
+                                    this.workingMemory );
+
+            // Now, needs to have 1 object in right memory
+            assertEquals( 1,
+                          this.memory.getFactHandleMemory().size() );
+
+            // simulate modify
+            this.node.retractObject( f1,
+                                     this.context,
+                                     this.workingMemory );
+            this.node.assertObject( f1,
+                                    this.context,
+                                    this.workingMemory );
+            // Memory should not change
+            assertEquals( 1,
+                          this.memory.getFactHandleMemory().size() );
+
+            // When this is retracter both tuples should assert
+            this.node.retractObject( f1,
+                                     this.context,
+                                     this.workingMemory );
+            assertEquals( 0,
+                          this.memory.getFactHandleMemory().size() );
+
+            // check memory sizes
+            assertEquals( 1,
+                          this.memory.getTupleMemory().size() );
+
+            // simulate modify
+            this.node.retractTuple( tuple1,
+                                    this.context,
+                                    this.workingMemory );
+            this.node.assertTuple( tuple1,
+                                   this.context,
+                                   this.workingMemory );
+            assertEquals( 1,
+                          this.memory.getTupleMemory().size() );
+            this.node.retractTuple( tuple1,
+                                    this.context,
+                                    this.workingMemory );
+            assertEquals( 0,
+                          this.memory.getTupleMemory().size() );
+        } catch ( final Exception e ) {
+            Assert.fail( "No exception should be raised in this procedure, but got: " + e.toString() );
+        }
+    }
+
+}


Property changes on: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/ExistsNodeTest.java
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:keywords
   + id author date revision
Name: svn:eol-style
   + native




More information about the jboss-svn-commits mailing list