[jboss-svn-commits] JBL Code SVN: r8841 - in labs/jbossrules/trunk/drools-core/src/main/java/org/drools: reteoo and 2 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Fri Jan 12 13:06:21 EST 2007


Author: tirelli
Date: 2007-01-12 13:06:12 -0500 (Fri, 12 Jan 2007)
New Revision: 8841

Added:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/TupleStartEqualsConstraint.java
Modified:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteTuple.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/RightInputAdapterNode.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/builder/GroupElementBuilder.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/Tuple.java
Log:
JBRULES-218: ReteooBuilder is now complete. Still need to fix tests

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/TupleStartEqualsConstraint.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/TupleStartEqualsConstraint.java	2007-01-12 17:53:17 UTC (rev 8840)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/TupleStartEqualsConstraint.java	2007-01-12 18:06:12 UTC (rev 8841)
@@ -0,0 +1,135 @@
+/*
+ * 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.common;
+
+import org.drools.reteoo.ReteTuple;
+import org.drools.rule.ContextEntry;
+import org.drools.rule.Declaration;
+import org.drools.spi.BetaNodeFieldConstraint;
+
+/**
+ * Checks if one tuple is the start subtuple of other tuple.
+ * For instance, if we have two tuples:
+ * 
+ * T1 = [ a, b, c ]
+ * T2 = [ a, b, c, d, e]
+ * 
+ * This constraint will evaluate to true as T1 is the starting subtuple
+ * of T2. On the other hand, if we have:
+ * 
+ * T1 = [ a, c, b ]
+ * T2 = [ a, b, c, d, e ]
+ * 
+ * This constraint will evaluate to false, as T1 is not the starting subtuple
+ * of T2. Besides having the same elements, the order is different.
+ * 
+ * This constraint is used when joining subnetworks back into the main 
+ * network.
+ *
+ * @author etirelli
+ *
+ */
+public class TupleStartEqualsConstraint
+    implements
+    BetaNodeFieldConstraint {
+    
+    private static final long serialVersionUID = 7766998673828986129L;
+    
+    private final Declaration[] declarations     = new Declaration[0];
+    
+    private static final TupleStartEqualsConstraint INSTANCE = new TupleStartEqualsConstraint(); 
+
+    // this is a stateless constraint, so we can make it a singleton
+    private TupleStartEqualsConstraint() {
+    }
+    
+    public static TupleStartEqualsConstraint getInstance() {
+        return INSTANCE;
+    }
+
+    public Declaration[] getRequiredDeclarations() {
+        return this.declarations;
+    }
+
+    public ContextEntry getContextEntry() {
+        return new TupleStartEqualsConstraintContextEntry();
+    }
+
+    public boolean isAllowedCachedLeft(final ContextEntry context,
+                                       final Object object) {
+        // object MUST be a ReteTuple
+        ReteTuple tuple = ((ReteTuple)object).getSubTuple( ((TupleStartEqualsConstraintContextEntry) context).compareSize );
+        return ((TupleStartEqualsConstraintContextEntry) context).left.equals( tuple );
+    }
+
+    public boolean isAllowedCachedRight(final ReteTuple tuple,
+                                        final ContextEntry context) {
+        return tuple.equals(((TupleStartEqualsConstraintContextEntry) context).right);
+    }
+
+    public String toString() {
+        return "[ TupleStartEqualsConstraint ]";
+    }
+
+    public int hashCode() {
+        return 10;
+    }
+
+    public boolean equals(final Object object) {
+        if ( this.getClass() == object.getClass() ) {
+            return true;
+        }
+        return false;
+    }
+
+    public static class TupleStartEqualsConstraintContextEntry
+        implements
+        ContextEntry {
+
+        private static final long serialVersionUID = 5841221599619051196L;
+        
+        public ReteTuple        left;
+        public ReteTuple        right;
+        
+        // the size of the tuple to compare
+        public int              compareSize;
+
+        private ContextEntry entry;
+
+        public TupleStartEqualsConstraintContextEntry() {
+        }
+
+        public ContextEntry getNext() {
+            return this.entry;
+        }
+
+        public void setNext(final ContextEntry entry) {
+            this.entry = entry;
+        }
+
+        public void updateFromTuple(final InternalWorkingMemory workingMemory, final ReteTuple tuple) {
+            this.left = tuple;
+            this.compareSize = tuple.size();
+        } 
+
+        public void updateFromFactHandle(final InternalWorkingMemory workingMemory, final InternalFactHandle handle) {
+            // if it is not a rete tuple, then there is a bug in the engine...
+            // it MUST be a rete tuple
+            this.right = ((ReteTuple) handle.getObject()).getSubTuple( this.compareSize );
+        }
+    }
+}


Property changes on: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/TupleStartEqualsConstraint.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/ReteTuple.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteTuple.java	2007-01-12 17:53:17 UTC (rev 8840)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteTuple.java	2007-01-12 18:06:12 UTC (rev 8841)
@@ -179,4 +179,35 @@
         // we know the object is never null and always of the  type ReteTuple    
         return equals( (ReteTuple) object );
     }
+
+    public int size() {
+        return this.index+1;
+    }
+    
+    /**
+     * Returns the ReteTuple that contains the "elements"
+     * first elements in this tuple.
+     * 
+     * Use carefully as no cloning is made during this process.
+     * 
+     * This method is used by TupleStartEqualsConstraint when
+     * joining a subnetwork tuple into the main network tuple;
+     * 
+     * @param elements the number of elements to return, starting from
+     * the begining of the tuple
+     * 
+     * @return a ReteTuple containing the "elements" first elements
+     * of this tuple or null if "elements" is greater than size; 
+     */
+    public ReteTuple getSubTuple( int elements ) {
+        ReteTuple entry = this;
+        if( elements > this.size() ) {
+            int lastindex = elements-1;
+            
+            while ( entry.index != lastindex ) {
+                entry = entry.parent;
+            }
+        }
+        return entry;
+    }
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/RightInputAdapterNode.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/RightInputAdapterNode.java	2007-01-12 17:53:17 UTC (rev 8840)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/RightInputAdapterNode.java	2007-01-12 18:06:12 UTC (rev 8841)
@@ -16,54 +16,62 @@
  * limitations under the License.
  */
 
+import org.drools.RuleBaseConfiguration;
 import org.drools.common.BaseNode;
+import org.drools.common.InternalFactHandle;
 import org.drools.common.InternalWorkingMemory;
-import org.drools.rule.Column;
+import org.drools.common.NodeMemory;
+import org.drools.common.PropagationContextImpl;
 import org.drools.spi.PropagationContext;
+import org.drools.util.Iterator;
+import org.drools.util.ObjectHashMap;
+import org.drools.util.ObjectHashMap.ObjectEntry;
 
 /**
- * When joining two <code>Not<code>s together the resulting <code>Tuple</code> from the first Not
- * Must be adapted to <code>FActHandleImpl</code> so it can be propagated into the second not
+ * When joining a subnetwork into the main network again, RightInputAdapterNode adapts the 
+ * subnetwork's tuple into a fact in order right join it with the tuple being propagated in
+ * the main network.
  * 
  * @author <a href="mailto:mark.proctor at jboss.com">Mark Proctor</a>
  * @author <a href="mailto:bob at werken.com">Bob McWhirter</a>
+ * @author <a href="mailto:etirelli at redhat.com">Edson Tirelli</a>
  *
  */
 public class RightInputAdapterNode extends ObjectSource
     implements
-    TupleSink {
-    /**
-     * 
-     */
+    TupleSink,
+    NodeMemory {
+
     private static final long serialVersionUID = 320L;
 
     private final TupleSource tupleSource;
 
-    private final Column         column;
-
     /**
      * Constructor specifying the unique id of the node in the Rete network, the position of the propagating <code>FactHandleImpl</code> in
      * <code>ReteTuple</code> and the source that propagates the receive <code>ReteTuple<code>s.
      * 
      * @param id
      *      Unique id 
-     * @param column
-     *      The column which specifis the position of the <code>FactHandleImpl</code> in the <code>ReteTuple</code>
      * @param source
      *      The <code>TupleSource</code> which propagates the received <code>ReteTuple</code>
      */
     public RightInputAdapterNode(final int id,
-                                 final Column column,
                                  final TupleSource source) {
-
         super( id );
-        this.column = column;
         this.tupleSource = source;
+        this.setHasMemory( true );
     }
 
     /**
-     * Takes the asserted <code>ReteTuple</code> received from the <code>TupleSource</code> and extract and propagate
-     * its <code>FactHandleImpl</code> based on the column specified by te node.
+     * Creates and return the node memory
+     */
+    public Object createMemory(RuleBaseConfiguration config) {
+        return new ObjectHashMap();
+    }
+
+    /**
+     * Takes the asserted <code>ReteTuple</code> received from the <code>TupleSource</code> and 
+     * adapts it into a FactHandleImpl
      * 
      * @param tuple
      *            The asserted <code>ReteTuple</code>.
@@ -75,45 +83,77 @@
     public void assertTuple(final ReteTuple tuple,
                             final PropagationContext context,
                             final InternalWorkingMemory workingMemory) {
-        this.sink.propagateAssertObject( tuple.get( this.column.getOffset() ),
+
+        ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory( this );
+
+        // creating a dummy fact handle to wrap the tuple
+        final InternalFactHandle handle = workingMemory.getFactHandleFactory().newFactHandle( tuple );
+        // add it to a memory mapping
+        memory.put( tuple,
+                    handle );
+
+        // propagate it
+        this.sink.propagateAssertObject( handle,
                                          context,
                                          workingMemory );
     }
 
-    /* (non-Javadoc)
-     * @see org.drools.reteoo.RetractionCallback#retractTuple(org.drools.reteoo.ReteTuple, org.drools.spi.PropagationContext, org.drools.reteoo.WorkingMemoryImpl)
+    /**
+     * Retracts the corresponding tuple by retrieving and retracting
+     * the fact created for it
      */
     public void retractTuple(final ReteTuple tuple,
                              final PropagationContext context,
                              final InternalWorkingMemory workingMemory) {
-        this.sink.propagateRetractObject( tuple.get( this.column.getOffset() ),
+
+        ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory( this );
+
+        // retrieve handle from memory
+        final InternalFactHandle handle = (InternalFactHandle) memory.remove( tuple );
+
+        // propagate a retract for it
+        this.sink.propagateRetractObject( handle,
                                           context,
                                           workingMemory,
                                           true );
+
+        // destroy dummy handle
+        workingMemory.getFactHandleFactory().destroyFactHandle( handle );
     }
 
-    /* (non-Javadoc)
-     * @see org.drools.reteoo.BaseNode#attach()
-     */
     public void attach() {
         this.tupleSource.addTupleSink( this );
     }
 
     public void attach(final InternalWorkingMemory[] workingMemories) {
         attach();
-        // this node has no memory, no point requesting repropagation     
+
+        for ( int i = 0, length = workingMemories.length; i < length; i++ ) {
+            final InternalWorkingMemory workingMemory = workingMemories[i];
+            final PropagationContext propagationContext = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(),
+                                                                                      PropagationContext.RULE_ADDITION,
+                                                                                      null,
+                                                                                      null );
+            this.tupleSource.updateSink( this,
+                                         propagationContext,
+                                         workingMemory );
+        }
     }
 
-    /* (non-Javadoc)
-     * @see org.drools.reteoo.BaseNode#updateNewNode(org.drools.reteoo.WorkingMemoryImpl, org.drools.spi.PropagationContext)
-     */
     public void updateSink(final ObjectSink sink,
                            final PropagationContext context,
                            final InternalWorkingMemory workingMemory) {
-        this.tupleSource.updateSink( new TupleSinkAdapter( sink,
-                                                           this.column.getOffset() ),
-                                     context,
-                                     workingMemory );
+
+        final ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory( this );
+
+        final Iterator it = memory.iterator();
+
+        // iterates over all propagated handles and assert them to the new sink
+        for ( ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next() ) {
+            sink.assertObject( (InternalFactHandle) entry.getValue(),
+                               context,
+                               workingMemory );
+        }
     }
 
     public void remove(final BaseNode node,
@@ -126,44 +166,4 @@
                                  workingMemories );
     }
 
-    /**
-     * Used with the updateSink method, so that the parent ObjectSource
-     * can  update the  TupleSink
-     * @author mproctor
-     *
-     */
-    private static class TupleSinkAdapter
-        implements
-        TupleSink {
-
-        private static final long serialVersionUID = 1636299857108066554L;
-        private ObjectSink sink;
-        private int        column;
-
-        public TupleSinkAdapter(final ObjectSink sink,
-                                final int column) {
-            this.sink = sink;
-            this.column = column;
-        }
-
-        public void assertTuple(final ReteTuple tuple,
-                                final PropagationContext context,
-                                final InternalWorkingMemory workingMemory) {
-            this.sink.assertObject( tuple.get( this.column ),
-                                    context,
-                                    workingMemory );
-        }
-
-        public void modifyTuple(final ReteTuple tuple,
-                                final PropagationContext context,
-                                final InternalWorkingMemory workingMemory) {
-            throw new UnsupportedOperationException( "TupleSinkAdapter onlys supports assertObject method calls" );
-        }
-
-        public void retractTuple(final ReteTuple tuple,
-                                 final PropagationContext context,
-                                 final InternalWorkingMemory workingMemory) {
-            throw new UnsupportedOperationException( "TupleSinkAdapter onlys supports assertObject method calls" );
-        }
-    }
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/builder/GroupElementBuilder.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/builder/GroupElementBuilder.java	2007-01-12 17:53:17 UTC (rev 8840)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/builder/GroupElementBuilder.java	2007-01-12 18:06:12 UTC (rev 8841)
@@ -16,15 +16,20 @@
 
 package org.drools.reteoo.builder;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import org.drools.RuntimeDroolsException;
+import org.drools.common.TupleStartEqualsConstraint;
 import org.drools.reteoo.ExistsNode;
 import org.drools.reteoo.JoinNode;
 import org.drools.reteoo.LeftInputAdapterNode;
 import org.drools.reteoo.NotNode;
+import org.drools.reteoo.ObjectSource;
+import org.drools.reteoo.RightInputAdapterNode;
 import org.drools.reteoo.TupleSource;
 import org.drools.rule.Column;
 import org.drools.rule.GroupElement;
@@ -53,8 +58,6 @@
 
     /**
      * @inheritDoc
-     * 
-     * 
      */
     public void build(BuildContext context,
                       BuildUtils utils,
@@ -66,121 +69,19 @@
         builder.build( context,
                        utils,
                        rce );
-
-        //        for ( final Iterator it = subrule.getChildren().iterator(); it.hasNext(); ) {
-        //            final Object object = it.next();
-        //
-        //            if ( object instanceof EvalCondition ) {
-        //                final EvalCondition eval = (EvalCondition) object;
-        //                checkUnboundDeclarations( eval.getRequiredDeclarations() );
-        //                this.tupleSource = attachNode( new EvalConditionNode( this.id++,
-        //                                                                      this.tupleSource,
-        //                                                                      eval ) );
-        //                continue;
-        //            }
-        //
-        //            BetaConstraints binder = null;
-        //            Column column = null;
-        //
-        //            if ( object instanceof Column ) {
-        //                column = (Column) object;
-        //
-        //                // @REMOVEME after the milestone period
-        //                if ( (binder != null) && (binder != EmptyBetaConstraints.getInstance()) ) throw new RuntimeDroolsException( "This is a bug! Please report to Drools development team!" );
-        //
-        //                binder = attachColumn( (Column) object,
-        //                                       subrule,
-        //                                       this.removeIdentities );
-        //
-        //                // If a tupleSource does not exist then we need to adapt this
-        //                // into
-        //                // a TupleSource using LeftInputAdapterNode
-        //                if ( this.tupleSource == null ) {
-        //                    this.tupleSource = attachNode( new LeftInputAdapterNode( this.id++,
-        //                                                                             this.objectSource ) );
-        //
-        //                    // objectSource is created by the attachColumn method, if we
-        //                    // adapt this to
-        //                    // a TupleSource then we need to null the objectSource
-        //                    // reference.
-        //                    this.objectSource = null;
-        //                }
-        //            } else if ( object instanceof GroupElement ) {
-        //                // If its not a Column or EvalCondition then it can either be a Not or an Exists
-        //                GroupElement ce = (GroupElement) object;
-        //                while ( !(ce.getChildren().get( 0 ) instanceof Column) ) {
-        //                    ce = (GroupElement) ce.getChildren().get( 0 );
-        //                }
-        //                column = (Column) ce.getChildren().get( 0 );
-        //
-        //                // If a tupleSource does not exist then we need to adapt an
-        //                // InitialFact into a a TupleSource using LeftInputAdapterNode
-        //                if ( this.tupleSource == null ) {
-        //                    // adjusting offset as all tuples will now contain initial-fact at index 0
-        //                    this.currentOffsetAdjustment = 1;
-        //
-        //                    final ObjectSource objectSource = attachNode( new ObjectTypeNode( this.id++,
-        //                                                                                      new ClassObjectType( InitialFact.class ),
-        //                                                                                      this.rete,
-        //                                                                                      this.ruleBase.getConfiguration().getAlphaNodeHashingThreshold() ) );
-        //
-        //                    this.tupleSource = attachNode( new LeftInputAdapterNode( this.id++,
-        //                                                                             objectSource ) );
-        //                }
-        //
-        //                // @REMOVEME after the milestone period
-        //                if ( (binder != null) && (binder != EmptyBetaConstraints.getInstance()) ) throw new RuntimeDroolsException( "This is a bug! Please report to Drools development team!" );
-        //
-        //                binder = attachColumn( column,
-        //                                       subrule,
-        //                                       this.removeIdentities );
-        //            }
-        //
-        //            if ( (object instanceof GroupElement) && (((GroupElement) object).isNot()) ) {
-        //                attachNot( this.tupleSource,
-        //                           (GroupElement) object,
-        //                           this.objectSource,
-        //                           binder,
-        //                           column );
-        //                binder = null;
-        //            } else if ( (object instanceof GroupElement) && (((GroupElement) object).isExists()) ) {
-        //                attachExists( this.tupleSource,
-        //                              (GroupElement) object,
-        //                              this.objectSource,
-        //                              binder,
-        //                              column );
-        //                binder = null;
-        //            } else if ( object.getClass() == From.class ) {
-        //                attachFrom( this.tupleSource,
-        //                            (From) object );
-        //            } else if ( object.getClass() == Accumulate.class ) {
-        //                attachAccumulate( this.tupleSource,
-        //                                  subrule,
-        //                                  (Accumulate) object );
-        //            } else if ( object.getClass() == Collect.class ) {
-        //                attachCollect( this.tupleSource,
-        //                               subrule,
-        //                               (Collect) object );
-        //            } else if ( this.objectSource != null ) {
-        //                this.tupleSource = attachNode( new JoinNode( this.id++,
-        //                                                             this.tupleSource,
-        //                                                             this.objectSource,
-        //                                                             binder ) );
-        //                binder = null;
-        //            }
-        //        }
-
     }
 
     /**
      * @inheritDoc
      */
-    public boolean requiresLeftActivation( BuildUtils utils, RuleConditionElement rce ) {
+    public boolean requiresLeftActivation(BuildUtils utils,
+                                          RuleConditionElement rce) {
         GroupElement ge = (GroupElement) rce;
 
         ReteooComponentBuilder builder = (ReteooComponentBuilder) geBuilders.get( ge.getType() );
-        
-        return builder.requiresLeftActivation( utils, rce );
+
+        return builder.requiresLeftActivation( utils,
+                                               rce );
     }
 
     private static class AndBuilder
@@ -235,19 +136,21 @@
             }
         }
 
-        public boolean requiresLeftActivation(BuildUtils utils, RuleConditionElement rce) {
+        public boolean requiresLeftActivation(BuildUtils utils,
+                                              RuleConditionElement rce) {
             GroupElement and = (GroupElement) rce;
 
             // need to check this because in the case of an empty rule, the root AND
             // will have no child
-            if( and.getChildren().isEmpty() ) {
+            if ( and.getChildren().isEmpty() ) {
                 return true;
-            } 
-            
+            }
+
             RuleConditionElement child = (RuleConditionElement) and.getChildren().get( 0 );
             ReteooComponentBuilder builder = utils.getBuilderFor( child );
-            
-            return builder.requiresLeftActivation( utils, child );
+
+            return builder.requiresLeftActivation( utils,
+                                                   child );
         }
     }
 
@@ -264,8 +167,9 @@
             throw new RuntimeDroolsException( "BUG: Can't build a rete network with an inner OR group element" );
         }
 
-        public boolean requiresLeftActivation(BuildUtils utils, RuleConditionElement rce) {
-            return false;
+        public boolean requiresLeftActivation(BuildUtils utils,
+                                              RuleConditionElement rce) {
+            throw new RuntimeDroolsException( "BUG: Can't build a rete network with an inner OR group element" );
         }
     }
 
@@ -285,9 +189,10 @@
                           BuildUtils utils,
                           RuleConditionElement rce) {
             GroupElement not = (GroupElement) rce;
-            
-            // NOT must save current column index in order to restore it later
+
+            // NOT must save some context info to restore it later
             int currentColumnIndex = context.getCurrentColumnOffset();
+            TupleSource tupleSource = context.getTupleSource();
 
             // get child
             RuleConditionElement child = (RuleConditionElement) not.getChildren().get( 0 );
@@ -300,21 +205,37 @@
                            utils,
                            child );
 
-            // if child is a column 
-            if ( child instanceof Column ) {
-                // then no sub-network needed... just a simple NOT node
-                context.setTupleSource( (TupleSource) utils.attachNode( context,
-                                                                        new NotNode( context.getNextId(),
-                                                                                     context.getTupleSource(),
-                                                                                     context.getObjectSource(),
-                                                                                     context.getBetaconstraints() ) ) );
-                context.setBetaconstraints( null );
-                context.setObjectSource( null );
+            // if child is not a column adapt it into a subnetwork
+            if ( !(child instanceof Column) ) {
 
-            } else {
-                // TODO: otherwise attach subnetwork
+                // attach right input adapter node to convert tuple source into an object source
+                context.setObjectSource( (ObjectSource) utils.attachNode( context,
+                                                                          new RightInputAdapterNode( context.getNextId(),
+                                                                                                     context.getTupleSource() ) ) );
+
+                // restore tuple source from before the start of the sub network
+                context.setTupleSource( tupleSource );
+
+                // create a tuple start equals constraint and set it in the context
+                TupleStartEqualsConstraint constraint = TupleStartEqualsConstraint.getInstance();
+                List predicates = new ArrayList();
+                predicates.add( constraint );
+                context.setBetaconstraints( utils.createBetaNodeConstraint( context,
+                                                                            predicates ) );
+
             }
-            
+
+            // then attach the NOT node. It will work both as a simple not node
+            // or as subnetwork join node as the context was set appropriatelly
+            // in each case
+            context.setTupleSource( (TupleSource) utils.attachNode( context,
+                                                                    new NotNode( context.getNextId(),
+                                                                                 context.getTupleSource(),
+                                                                                 context.getObjectSource(),
+                                                                                 context.getBetaconstraints() ) ) );
+            context.setBetaconstraints( null );
+            context.setObjectSource( null );
+
             // restore column index
             context.setCurrentColumnOffset( currentColumnIndex );
         }
@@ -342,8 +263,9 @@
                           RuleConditionElement rce) {
             GroupElement exists = (GroupElement) rce;
 
-            // EXISTS must save current column index in order to restore it later
+            // EXISTS must save some context info to restore it later
             int currentColumnIndex = context.getCurrentColumnOffset();
+            TupleSource tupleSource = context.getTupleSource();
 
             // get child
             RuleConditionElement child = (RuleConditionElement) exists.getChildren().get( 0 );
@@ -356,21 +278,37 @@
                            utils,
                            child );
 
-            // if child is a column 
-            if ( child instanceof Column ) {
-                // then no sub-network needed... just a simple EXISTS node
-                context.setTupleSource( (TupleSource) utils.attachNode( context,
-                                                                        new ExistsNode( context.getNextId(),
-                                                                                     context.getTupleSource(),
-                                                                                     context.getObjectSource(),
-                                                                                     context.getBetaconstraints() ) ) );
-                context.setBetaconstraints( null );
-                context.setObjectSource( null );
+            // if child is not a column adapt it into a subnetwork
+            if ( !(child instanceof Column) ) {
 
-            } else {
-                // TODO: otherwise attach subnetwork
+                // attach right input adapter node to convert tuple source into an object source
+                context.setObjectSource( (ObjectSource) utils.attachNode( context,
+                                                                          new RightInputAdapterNode( context.getNextId(),
+                                                                                                     context.getTupleSource() ) ) );
+
+                // restore tuple source from before the start of the sub network
+                context.setTupleSource( tupleSource );
+
+                // create a tuple start equals constraint and set it in the context
+                TupleStartEqualsConstraint constraint = TupleStartEqualsConstraint.getInstance();
+                List predicates = new ArrayList();
+                predicates.add( constraint );
+                context.setBetaconstraints( utils.createBetaNodeConstraint( context,
+                                                                            predicates ) );
+
             }
-            
+
+            // then attach the EXISTS node. It will work both as a simple exists node
+            // or as subnetwork join node as the context was set appropriatelly
+            // in each case
+            context.setTupleSource( (TupleSource) utils.attachNode( context,
+                                                                    new ExistsNode( context.getNextId(),
+                                                                                    context.getTupleSource(),
+                                                                                    context.getObjectSource(),
+                                                                                    context.getBetaconstraints() ) ) );
+            context.setBetaconstraints( null );
+            context.setObjectSource( null );
+
             // restore column index
             context.setCurrentColumnOffset( currentColumnIndex );
         }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/Tuple.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/Tuple.java	2007-01-12 17:53:17 UTC (rev 8840)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/Tuple.java	2007-01-12 18:06:12 UTC (rev 8841)
@@ -57,6 +57,16 @@
 
     InternalFactHandle[] getFactHandles();
 
+    /**
+     * Returns the tuple recency
+     * @return
+     */
     long getRecency();
+    
+    /**
+     * Returns the size of this tuple in number of elements (columns)
+     * @return
+     */
+    int size();
 
 }
\ No newline at end of file




More information about the jboss-svn-commits mailing list