public void testLiteralConstraintAssertSequentialMode() throws Exception {
    RuleBaseConfiguration config = new RuleBaseConfiguration();
    config.setSequential(true);
    ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase(config);
    BuildContext buildContext =
        new BuildContext(ruleBase, ((ReteooRuleBase) ruleBase).getReteooBuilder().getIdGenerator());
    ReteooWorkingMemory workingMemory = new ReteooWorkingMemory(buildContext.getNextId(), ruleBase);

    final Rule rule = new Rule("test-rule");
    final PropagationContext context =
        new PropagationContextImpl(0, PropagationContext.ASSERTION, null, null);

    final MockObjectSource source = new MockObjectSource(buildContext.getNextId());

    final ClassFieldExtractor extractor =
        cache.getExtractor(Cheese.class, "type", getClass().getClassLoader());

    final FieldValue field = FieldFactory.getFieldValue("cheddar");

    final Evaluator evaluator = ValueType.OBJECT_TYPE.getEvaluator(Operator.EQUAL);

    final LiteralConstraint constraint = new LiteralConstraint(extractor, evaluator, field);

    // With Memory
    final AlphaNode alphaNode =
        new AlphaNode(buildContext.getNextId(), constraint, source, buildContext); // has memory

    final MockObjectSink sink = new MockObjectSink();
    alphaNode.addObjectSink(sink);

    final Cheese cheddar = new Cheese("cheddar", 5);
    final DefaultFactHandle f0 = (DefaultFactHandle) workingMemory.insert(cheddar);

    // check sink is empty
    assertLength(0, sink.getAsserted());

    // check alpha memory is empty
    final AlphaMemory memory = (AlphaMemory) workingMemory.getNodeMemory(alphaNode);

    assertNull(memory.facts);

    // object should assert as it passes text
    alphaNode.assertObject(f0, context, workingMemory);

    assertEquals(1, sink.getAsserted().size());
    assertNull(memory.facts);
    Object[] list = (Object[]) sink.getAsserted().get(0);
    assertSame(cheddar, workingMemory.getObject((DefaultFactHandle) list[0]));

    final Cheese stilton = new Cheese("stilton", 6);
    final DefaultFactHandle f1 = new DefaultFactHandle(1, stilton);

    // object should NOT assert as it does not pass test
    alphaNode.assertObject(f1, context, workingMemory);

    assertLength(1, sink.getAsserted());
    assertNull(memory.facts);
    list = (Object[]) sink.getAsserted().get(0);
    assertSame(cheddar, workingMemory.getObject((DefaultFactHandle) list[0]));
  }
  public void testRetractObjectWithMemory() throws Exception {
    RuleBaseConfiguration config = new RuleBaseConfiguration();
    config.setAlphaMemory(true);
    ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase(config);
    BuildContext buildContext =
        new BuildContext(ruleBase, ((ReteooRuleBase) ruleBase).getReteooBuilder().getIdGenerator());
    ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase.newStatefulSession();

    final Rule rule = new Rule("test-rule");
    final PropagationContext context =
        new PropagationContextImpl(0, PropagationContext.ASSERTION, null, null);

    final MockObjectSource source = new MockObjectSource(buildContext.getNextId());

    final FieldExtractor extractor =
        cache.getExtractor(Cheese.class, "type", getClass().getClassLoader());

    final FieldValue field = FieldFactory.getFieldValue("cheddar");

    final Evaluator evaluator = ValueType.OBJECT_TYPE.getEvaluator(Operator.EQUAL);

    final LiteralConstraint constraint = new LiteralConstraint(extractor, evaluator, field);

    buildContext.setAlphaNodeMemoryAllowed(true);
    final AlphaNode alphaNode =
        new AlphaNode(buildContext.getNextId(), constraint, source, buildContext); // has memory
    final MockObjectSink sink = new MockObjectSink();
    alphaNode.addObjectSink(sink);

    final Cheese cheddar = new Cheese("cheddar", 5);

    final DefaultFactHandle f0 = new DefaultFactHandle(0, cheddar);

    // check alpha memory is empty
    final AlphaMemory memory = (AlphaMemory) workingMemory.getNodeMemory(alphaNode);
    assertEquals(0, memory.facts.size());

    // object should assert as it passes text
    alphaNode.assertObject(f0, context, workingMemory);

    assertEquals(1, memory.facts.size());

    final DefaultFactHandle f1 = new DefaultFactHandle(1, "cheese");

    // object should NOT retract as it doesn't exist
    alphaNode.retractObject(f1, context, workingMemory);

    assertLength(0, sink.getRetracted());
    assertEquals(1, memory.facts.size());
    assertTrue("Should contain 'cheddar handle'", memory.facts.contains(f0));

    // object should retract as it does exist
    alphaNode.retractObject(f0, context, workingMemory);

    assertLength(1, sink.getRetracted());
    assertEquals(0, memory.facts.size());
    final Object[] list = (Object[]) sink.getRetracted().get(0);
    assertSame(f0, list[0]);
  }
Beispiel #3
0
  @Test
  public void testLiteralConstraintAssertObjectWithoutMemory() throws Exception {
    ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase();
    BuildContext buildContext =
        new BuildContext(ruleBase, ((ReteooRuleBase) ruleBase).getReteooBuilder().getIdGenerator());
    ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase.newStatefulSession();

    final Rule rule = new Rule("test-rule");
    final PropagationContext context =
        new PropagationContextImpl(0, PropagationContext.INSERTION, null, null, null);

    final MockObjectSource source = new MockObjectSource(buildContext.getNextId());

    final ClassFieldReader extractor =
        store.getReader(Cheese.class, "type", getClass().getClassLoader());

    final FieldValue field = FieldFactory.getInstance().getFieldValue("cheddar");

    final MvelConstraint constraint =
        new MvelConstraintTestUtil("type == \"cheddar\"", field, extractor);

    // With Memory
    final AlphaNode alphaNode =
        new AlphaNode(buildContext.getNextId(), constraint, source, buildContext); // no memory

    final MockObjectSink sink = new MockObjectSink();
    alphaNode.addObjectSink(sink);

    final Cheese cheddar = new Cheese("cheddar", 5);
    final DefaultFactHandle f0 = (DefaultFactHandle) workingMemory.insert(cheddar);

    // check sink is empty
    assertLength(0, sink.getAsserted());

    // check alpha memory is empty
    final AlphaMemory memory = (AlphaMemory) workingMemory.getNodeMemory(alphaNode);

    // object should assert as it passes text
    alphaNode.assertObject(f0, context, workingMemory);

    assertEquals(1, sink.getAsserted().size());

    Object[] list = (Object[]) sink.getAsserted().get(0);
    assertSame(cheddar, workingMemory.getObject((DefaultFactHandle) list[0]));

    final Cheese stilton = new Cheese("stilton", 6);
    final DefaultFactHandle f1 = new DefaultFactHandle(1, stilton);

    // object should NOT assert as it does not pass test
    alphaNode.assertObject(f1, context, workingMemory);

    assertLength(1, sink.getAsserted());

    list = (Object[]) sink.getAsserted().get(0);
    assertSame(cheddar, workingMemory.getObject((DefaultFactHandle) list[0]));
  }
Beispiel #4
0
 protected void initInferredMask(LeftTupleSource leftInput) {
   LeftTupleSource unwrappedLeft = unwrapLeftInput(leftInput);
   if (unwrappedLeft.getType() == NodeTypeEnums.LeftInputAdapterNode
       && ((LeftInputAdapterNode) unwrappedLeft).getParentObjectSource().getType()
           == NodeTypeEnums.AlphaNode) {
     AlphaNode alphaNode =
         (AlphaNode) ((LeftInputAdapterNode) unwrappedLeft).getParentObjectSource();
     leftInferredMask = alphaNode.updateMask(leftDeclaredMask);
   } else {
     leftInferredMask = leftDeclaredMask;
   }
   leftInferredMask = leftInferredMask.resetAll(leftNegativeMask);
 }
Beispiel #5
0
  @Override
  protected void initInferredMask(LeftTupleSource leftInput) {
    super.initInferredMask(leftInput);

    ObjectSource unwrappedRight = unwrapRightInput();
    if (unwrappedRight instanceof AlphaNode) {
      AlphaNode alphaNode = (AlphaNode) unwrappedRight;
      rightInferredMask = alphaNode.updateMask(rightDeclaredMask);
    } else {
      rightInferredMask = rightDeclaredMask;
    }
    rightInferredMask &= (Long.MAX_VALUE - rightNegativeMask);
  }
  /*
   * dont need to test with and without memory on this, as it was already done
   * on the previous two tests. This just test AlphaNode With a different
   * Constraint type.
   */
  public void testReturnValueConstraintAssertObject() throws Exception {
    RuleBaseConfiguration config = new RuleBaseConfiguration();
    config.setAlphaMemory(false);
    ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase(config);
    BuildContext buildContext =
        new BuildContext(ruleBase, ((ReteooRuleBase) ruleBase).getReteooBuilder().getIdGenerator());
    ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase.newStatefulSession();

    final Rule rule = new Rule("test-rule");
    final PropagationContext context =
        new PropagationContextImpl(0, PropagationContext.ASSERTION, null, null);

    final MockObjectSource source = new MockObjectSource(buildContext.getNextId());

    final FieldExtractor extractor =
        cache.getExtractor(Cheese.class, "type", getClass().getClassLoader());

    final FieldValue field = FieldFactory.getFieldValue("cheddar");

    final Evaluator evaluator = ValueType.OBJECT_TYPE.getEvaluator(Operator.EQUAL);

    final LiteralConstraint constraint = new LiteralConstraint(extractor, evaluator, field);

    final AlphaNode alphaNode =
        new AlphaNode(buildContext.getNextId(), constraint, source, buildContext);
    final MockObjectSink sink = new MockObjectSink();
    alphaNode.addObjectSink(sink);

    final Cheese cheddar = new Cheese("cheddar", 5);

    final DefaultFactHandle f0 = (DefaultFactHandle) workingMemory.insert(cheddar);

    assertLength(0, sink.getAsserted());

    // object should assert as it passes text
    alphaNode.assertObject(f0, context, workingMemory);

    assertLength(1, sink.getAsserted());
    final Object[] list = (Object[]) sink.getAsserted().get(0);
    assertSame(cheddar, workingMemory.getObject((DefaultFactHandle) list[0]));

    final Cheese stilton = new Cheese("stilton", 6);
    f0.setObject(stilton);

    sink.getAsserted().clear();

    // object should not assert as it does not pass text
    alphaNode.assertObject(f0, context, workingMemory);

    assertLength(0, sink.getAsserted());
  }
  public void testIsMemoryAllowedOverride() throws Exception {
    RuleBaseConfiguration config = new RuleBaseConfiguration();
    config.setAlphaMemory(true);
    ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase(config);
    BuildContext buildContext =
        new BuildContext(ruleBase, ((ReteooRuleBase) ruleBase).getReteooBuilder().getIdGenerator());
    ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase.newStatefulSession();

    final Rule rule = new Rule("test-rule");
    final PropagationContext context =
        new PropagationContextImpl(0, PropagationContext.ASSERTION, null, null);

    final MockObjectSource source = new MockObjectSource(buildContext.getNextId());

    final ClassFieldExtractor extractor =
        cache.getExtractor(Cheese.class, "type", getClass().getClassLoader());

    final FieldValue field = FieldFactory.getFieldValue("cheddar");

    final Evaluator evaluator = ValueType.OBJECT_TYPE.getEvaluator(Operator.EQUAL);

    final LiteralConstraint constraint = new LiteralConstraint(extractor, evaluator, field);

    // With Memory
    buildContext.setAlphaNodeMemoryAllowed(false);
    final AlphaNode alphaNode =
        new AlphaNode(buildContext.getNextId(), constraint, source, buildContext); // has memory

    final MockObjectSink sink = new MockObjectSink();
    alphaNode.addObjectSink(sink);

    final Cheese cheddar = new Cheese("cheddar", 5);
    final DefaultFactHandle f0 = (DefaultFactHandle) workingMemory.insert(cheddar);

    // check sink is empty
    assertLength(0, sink.getAsserted());

    // check alpha memory is empty
    final AlphaMemory memory = (AlphaMemory) workingMemory.getNodeMemory(alphaNode);

    assertNull(memory.facts);

    // object should assert as it passes text
    alphaNode.assertObject(f0, context, workingMemory);

    assertEquals(1, sink.getAsserted().size());
    // memory should be one, as even though isAlphaMemory is on for the configuration, the build
    // never allows memory
    assertNull(memory.facts);
  }
  public void byPassModifyToBetaNode(
      final InternalFactHandle factHandle,
      final ModifyPreviousTuples modifyPreviousTuples,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    final Object object = factHandle.getObject();

    // We need to iterate in the same order as the assert
    if (this.hashedFieldIndexes != null) {
      // Iterate the FieldIndexes to see if any are hashed
      for (FieldIndex fieldIndex = this.hashedFieldIndexes.getFirst();
          fieldIndex != null;
          fieldIndex = fieldIndex.getNext()) {
        if (!fieldIndex.isHashed()) {
          continue;
        }
        // this field is hashed so set the existing hashKey and see if there is a sink for it
        final AlphaNode sink = (AlphaNode) this.hashedSinkMap.get(new HashKey(fieldIndex, object));
        if (sink != null) {
          // only alpha nodes are hashable
          sink.getObjectSinkPropagator()
              .byPassModifyToBetaNode(factHandle, modifyPreviousTuples, context, workingMemory);
        }
      }
    }

    // propagate unhashed
    if (this.hashableSinks != null) {
      for (ObjectSinkNode sink = this.hashableSinks.getFirst();
          sink != null;
          sink = sink.getNextObjectSinkNode()) {
        // only alpha nodes are hashable
        ((AlphaNode) sink)
            .getObjectSinkPropagator()
            .byPassModifyToBetaNode(factHandle, modifyPreviousTuples, context, workingMemory);
      }
    }

    if (this.otherSinks != null) {
      // propagate others
      for (ObjectSinkNode sink = this.otherSinks.getFirst();
          sink != null;
          sink = sink.getNextObjectSinkNode()) {
        // compound alpha, lianode or betanode
        sink.byPassModifyToBetaNode(factHandle, modifyPreviousTuples, context, workingMemory);
      }
    }
  }
  public void propagateModifyObject(
      final InternalFactHandle factHandle,
      final ModifyPreviousTuples modifyPreviousTuples,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    final Object object = factHandle.getObject();

    // Iterates the FieldIndex collection, which tells you if particularly field is hashed or not
    // if the field is hashed then it builds the hashkey to return the correct sink for the current
    // objects slot's
    // value, one object may have multiple fields indexed.
    if (this.hashedFieldIndexes != null) {
      // Iterate the FieldIndexes to see if any are hashed
      for (FieldIndex fieldIndex = this.hashedFieldIndexes.getFirst();
          fieldIndex != null;
          fieldIndex = fieldIndex.getNext()) {
        if (!fieldIndex.isHashed()) {
          continue;
        }
        // this field is hashed so set the existing hashKey and see if there is a sink for it
        final AlphaNode sink = (AlphaNode) this.hashedSinkMap.get(new HashKey(fieldIndex, object));
        if (sink != null) {
          // go straight to the AlphaNode's propagator, as we know it's true and no need to retest
          sink.getObjectSinkPropagator()
              .propagateModifyObject(factHandle, modifyPreviousTuples, context, workingMemory);
        }
      }
    }

    // propagate unhashed
    if (this.hashableSinks != null) {
      for (ObjectSinkNode sink = this.hashableSinks.getFirst();
          sink != null;
          sink = sink.getNextObjectSinkNode()) {
        doPropagateModifyObject(factHandle, modifyPreviousTuples, context, workingMemory, sink);
      }
    }

    if (this.otherSinks != null) {
      // propagate others
      for (ObjectSinkNode sink = this.otherSinks.getFirst();
          sink != null;
          sink = sink.getNextObjectSinkNode()) {
        doPropagateModifyObject(factHandle, modifyPreviousTuples, context, workingMemory, sink);
      }
    }
  }
  public ObjectSinkPropagator removeObjectSink(final ObjectSink sink) {
    this.sinks = null; // dirty it, so it'll rebuild on next get
    if (sink.getType() == NodeTypeEnums.AlphaNode) {
      final AlphaNode alphaNode = (AlphaNode) sink;
      final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();

      if (fieldConstraint instanceof IndexableConstraint) {
        final IndexableConstraint indexableConstraint = (IndexableConstraint) fieldConstraint;
        final FieldValue value = indexableConstraint.getField();

        if (isHashable(indexableConstraint)) {
          final InternalReadAccessor fieldAccessor = indexableConstraint.getFieldExtractor();
          final int index = fieldAccessor.getIndex();
          final FieldIndex fieldIndex = unregisterFieldIndex(index);

          if (fieldIndex.isHashed()) {
            HashKey hashKey = new HashKey(index, value, fieldAccessor);
            this.hashedSinkMap.remove(hashKey);
            if (fieldIndex.getCount() <= this.alphaNodeHashingThreshold - 1) {
              // we have less than three so unhash
              unHashSinks(fieldIndex);
            }
          } else {
            this.hashableSinks.remove(alphaNode);
          }

          if (this.hashableSinks != null && this.hashableSinks.isEmpty()) {
            this.hashableSinks = null;
          }

          return size() == 1 ? new SingleObjectSinkAdapter(getSinks()[0]) : this;
        }
      }
    }

    this.otherSinks.remove((ObjectSinkNode) sink);

    if (this.otherSinks.isEmpty()) {
      this.otherSinks = null;
    }

    return size() == 1 ? new SingleObjectSinkAdapter(getSinks()[0]) : this;
  }
 static InternalReadAccessor getHashableAccessor(AlphaNode alphaNode) {
   AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
   if (fieldConstraint instanceof IndexableConstraint) {
     IndexableConstraint indexableConstraint = (IndexableConstraint) fieldConstraint;
     if (isHashable(indexableConstraint)) {
       return indexableConstraint.getFieldExtractor();
     }
   }
   return null;
 }
  public ObjectSinkPropagator addObjectSink(ObjectSink sink, int alphaNodeHashingThreshold) {
    this.sinks = null; // dirty it, so it'll rebuild on next get
    if (sink.getType() == NodeTypeEnums.AlphaNode) {
      final AlphaNode alphaNode = (AlphaNode) sink;
      final InternalReadAccessor readAccessor = getHashableAccessor(alphaNode);

      if (readAccessor != null) {
        final int index = readAccessor.getIndex();
        final FieldIndex fieldIndex = registerFieldIndex(index, readAccessor);

        // DROOLS-678 : prevent null values from being hashed as 0s
        final FieldValue value = ((IndexableConstraint) alphaNode.getConstraint()).getField();
        if (fieldIndex.getCount() >= this.alphaNodeHashingThreshold
            && this.alphaNodeHashingThreshold != 0
            && !value.isNull()) {
          if (!fieldIndex.isHashed()) {
            hashSinks(fieldIndex);
          }

          // no need to check, we know  the sink  does not exist
          this.hashedSinkMap.put(
              new HashKey(index, value, fieldIndex.getFieldExtractor()), alphaNode, false);
        } else {
          if (this.hashableSinks == null) {
            this.hashableSinks = new ObjectSinkNodeList();
          }
          this.hashableSinks.add(alphaNode);
        }
        return this;
      }
    }

    if (this.otherSinks == null) {
      this.otherSinks = new ObjectSinkNodeList();
    }

    this.otherSinks.add((ObjectSinkNode) sink);
    return this;
  }
  void unHashSinks(final FieldIndex fieldIndex) {
    final int index = fieldIndex.getIndex();
    // this is the list of sinks that need to be removed from the hashedSinkMap
    final List<HashKey> unhashedSinks = new ArrayList<HashKey>();

    final Iterator iter = this.hashedSinkMap.newIterator();
    ObjectHashMap.ObjectEntry entry = (ObjectHashMap.ObjectEntry) iter.next();

    while (entry != null) {
      final AlphaNode alphaNode = (AlphaNode) entry.getValue();
      final IndexableConstraint indexableConstraint =
          (IndexableConstraint) alphaNode.getConstraint();

      // only alpha nodes that have an Operator.EQUAL are in sinks, so only check if it is
      // the right field index
      if (index == indexableConstraint.getFieldExtractor().getIndex()) {
        final FieldValue value = indexableConstraint.getField();
        if (this.hashableSinks == null) {
          this.hashableSinks = new ObjectSinkNodeList();
        }
        this.hashableSinks.add(alphaNode);

        unhashedSinks.add(new HashKey(index, value, fieldIndex.getFieldExtractor()));
      }

      entry = (ObjectHashMap.ObjectEntry) iter.next();
    }

    for (HashKey hashKey : unhashedSinks) {
      this.hashedSinkMap.remove(hashKey);
    }

    if (this.hashedSinkMap.isEmpty()) {
      this.hashedSinkMap = null;
    }

    fieldIndex.setHashed(false);
  }
  void hashSinks(final FieldIndex fieldIndex) {
    if (this.hashedSinkMap == null) {
      this.hashedSinkMap = new ObjectHashMap();
    }

    final int index = fieldIndex.getIndex();
    final InternalReadAccessor fieldReader = fieldIndex.getFieldExtractor();

    ObjectSinkNode currentSink = this.hashableSinks.getFirst();

    while (currentSink != null) {
      final AlphaNode alphaNode = (AlphaNode) currentSink;
      final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
      final IndexableConstraint indexableConstraint = (IndexableConstraint) fieldConstraint;

      // position to the next sink now because alphaNode may be removed if the index is equal. If we
      // were to do this
      // afterwards, currentSink.nextNode would be null
      currentSink = currentSink.getNextObjectSinkNode();

      // only alpha nodes that have an Operator.EQUAL are in hashableSinks, so only check if it is
      // the right field index
      if (index == indexableConstraint.getFieldExtractor().getIndex()) {
        final FieldValue value = indexableConstraint.getField();
        this.hashedSinkMap.put(new HashKey(index, value, fieldReader), alphaNode);

        // remove the alpha from the possible candidates of hashable sinks since it is now hashed
        hashableSinks.remove(alphaNode);
      }
    }

    if (this.hashableSinks.isEmpty()) {
      this.hashableSinks = null;
    }

    fieldIndex.setHashed(true);
  }
Beispiel #15
0
  @Test
  public void testUpdateSinkWithoutMemory() throws FactException, IntrospectionException {
    // An AlphaNode should try and repropagate from its source
    ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase();
    BuildContext buildContext =
        new BuildContext(ruleBase, ((ReteooRuleBase) ruleBase).getReteooBuilder().getIdGenerator());
    ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase.newStatefulSession();

    final Rule rule = new Rule("test-rule");
    final PropagationContext context =
        new PropagationContextImpl(0, PropagationContext.INSERTION, null, null, null);

    final MockObjectSource source = new MockObjectSource(buildContext.getNextId());

    final InternalReadAccessor extractor =
        store.getReader(Cheese.class, "type", getClass().getClassLoader());

    final FieldValue field = FieldFactory.getInstance().getFieldValue("cheddar");

    final MvelConstraint constraint =
        new MvelConstraintTestUtil("type == \"cheddar\"", field, extractor);

    final AlphaNode alphaNode =
        new AlphaNode(buildContext.getNextId(), constraint, source, buildContext); // no memory

    alphaNode.attach();

    final MockObjectSink sink1 = new MockObjectSink();
    alphaNode.addObjectSink(sink1);

    // Assert a single fact which should be in the AlphaNode memory and also
    // propagated to the
    // the tuple sink
    final Cheese cheese = new Cheese("cheddar", 0);
    final DefaultFactHandle handle1 = new DefaultFactHandle(1, cheese);
    // adding handle to the mock source
    source.addFact(handle1);

    alphaNode.assertObject(handle1, context, workingMemory);

    // Create a fact that should not be propagated, since the alpha node restriction will filter it
    // out
    final Cheese stilton = new Cheese("stilton", 10);
    final DefaultFactHandle handle2 = new DefaultFactHandle(2, stilton);
    // adding handle to the mock source
    source.addFact(handle2);

    alphaNode.assertObject(handle2, context, workingMemory);

    assertLength(1, sink1.getAsserted());

    // Attach a new tuple sink
    final MockObjectSink sink2 = new MockObjectSink();

    // Tell the alphanode to update the new node. Make sure the first sink1
    // is not updated
    // likewise the source should not do anything
    alphaNode.updateSink(sink2, context, workingMemory);

    assertLength(1, sink1.getAsserted());
    assertLength(1, sink2.getAsserted());
    assertEquals(1, source.getUdated());
  }
  public void testQueryTerminalNode() {
    final ClassObjectType queryObjectType = new ClassObjectType(DroolsQuery.class);
    final ObjectTypeNode queryObjectTypeNode =
        new ObjectTypeNode(this.buildContext.getNextId(), queryObjectType, buildContext);
    queryObjectTypeNode.attach();

    ClassFieldExtractor extractor =
        cache.getExtractor(DroolsQuery.class, "name", DroolsQuery.class.getClassLoader());

    FieldValue field = FieldFactory.getFieldValue("query-1");

    final Evaluator evaluator = ValueType.STRING_TYPE.getEvaluator(Operator.EQUAL);
    LiteralConstraint constraint = new LiteralConstraint(extractor, evaluator, field);

    AlphaNode alphaNode =
        new AlphaNode(this.buildContext.getNextId(), constraint, queryObjectTypeNode, buildContext);
    alphaNode.attach();

    final LeftInputAdapterNode liaNode =
        new LeftInputAdapterNode(this.buildContext.getNextId(), alphaNode, this.buildContext);
    liaNode.attach();

    final ClassObjectType cheeseObjectType = new ClassObjectType(Cheese.class);
    final ObjectTypeNode cheeseObjectTypeNode =
        new ObjectTypeNode(this.buildContext.getNextId(), cheeseObjectType, buildContext);
    cheeseObjectTypeNode.attach();

    extractor = cache.getExtractor(Cheese.class, "type", getClass().getClassLoader());

    field = FieldFactory.getFieldValue("stilton");

    constraint = new LiteralConstraint(extractor, evaluator, field);

    alphaNode =
        new AlphaNode(
            this.buildContext.getNextId(), constraint, cheeseObjectTypeNode, buildContext);
    alphaNode.attach();

    BuildContext buildContext =
        new BuildContext(ruleBase, ruleBase.getReteooBuilder().getIdGenerator());
    buildContext.setTupleMemoryEnabled(false);

    final JoinNode joinNode =
        new JoinNode(
            this.buildContext.getNextId(),
            liaNode,
            alphaNode,
            EmptyBetaConstraints.getInstance(),
            buildContext);
    joinNode.attach();

    final Query query = new Query("query-1");

    final QueryTerminalNode queryNode =
        new QueryTerminalNode(this.buildContext.getNextId(), joinNode, query, query.getLhs());

    queryNode.attach();

    final org.drools.rule.Package pkg = new org.drools.rule.Package("com.drools.test");
    pkg.addRule(query);

    try {
      final Field pkgField = ruleBase.getClass().getSuperclass().getDeclaredField("pkgs");
      pkgField.setAccessible(true);
      final Map pkgs = (Map) pkgField.get(ruleBase);
      pkgs.put(pkg.getName(), pkg);
    } catch (final Exception e) {
      Assert.fail("Should not throw any exception: " + e.getMessage());
    }

    final WorkingMemory workingMemory = ruleBase.newStatefulSession();
    QueryResults results = workingMemory.getQueryResults("query-1");

    assertEquals(0, results.size());

    final Cheese stilton1 = new Cheese("stilton", 100);
    final FactHandle handle1 = workingMemory.insert(stilton1);

    results = workingMemory.getQueryResults("query-1");

    assertEquals(1, results.size());

    final Cheese cheddar = new Cheese("cheddar", 55);
    workingMemory.insert(cheddar);

    results = workingMemory.getQueryResults("query-1");

    assertEquals(1, results.size());

    final Cheese stilton2 = new Cheese("stilton", 5);

    final FactHandle handle2 = workingMemory.insert(stilton2);

    results = workingMemory.getQueryResults("query-1");

    assertEquals(2, results.size());

    QueryResult result = results.get(0);
    assertEquals(1, result.size());
    assertEquals(stilton2, result.get(0));

    result = results.get(1);
    assertEquals(1, result.size());
    assertEquals(stilton1, result.get(0));

    int i = 0;
    for (final Iterator it = results.iterator(); it.hasNext(); ) {
      result = (QueryResult) it.next();
      assertEquals(1, result.size());
      if (i == 1) {
        assertSame(stilton1, result.get(0));
      } else {
        assertSame(stilton2, result.get(0));
      }
      i++;
    }

    workingMemory.retract(handle1);
    results = workingMemory.getQueryResults("query-1");

    assertEquals(1, results.size());

    workingMemory.retract(handle2);
    results = workingMemory.getQueryResults("query-1");

    assertEquals(0, results.size());
  }
  @Test
  public void testQueryTerminalNode() {
    final ClassObjectType queryObjectType = new ClassObjectType(DroolsQuery.class);
    final ObjectTypeNode queryObjectTypeNode =
        new ObjectTypeNode(
            this.buildContext.getNextId(), this.entryPoint, queryObjectType, buildContext);
    queryObjectTypeNode.attach(buildContext);

    ClassFieldReader extractor = store.getReader(DroolsQuery.class, "name");

    MvelConstraint constraint =
        new MvelConstraintTestUtil(
            "name == \"query-1\"", FieldFactory.getInstance().getFieldValue("query-1"), extractor);

    final QueryImpl query = new QueryImpl("query-1");
    buildContext.setRule(query);
    AlphaNode alphaNode =
        new AlphaNode(this.buildContext.getNextId(), constraint, queryObjectTypeNode, buildContext);
    alphaNode.attach(buildContext);

    final LeftInputAdapterNode liaNode =
        new LeftInputAdapterNode(this.buildContext.getNextId(), alphaNode, this.buildContext);
    liaNode.attach(buildContext);

    final ClassObjectType cheeseObjectType = new ClassObjectType(Cheese.class);
    final ObjectTypeNode cheeseObjectTypeNode =
        new ObjectTypeNode(
            this.buildContext.getNextId(), this.entryPoint, cheeseObjectType, buildContext);
    cheeseObjectTypeNode.attach(buildContext);

    extractor = store.getReader(Cheese.class, "type");

    constraint =
        new MvelConstraintTestUtil(
            "type == \"stilton\"", FieldFactory.getInstance().getFieldValue("stilton"), extractor);

    alphaNode =
        new AlphaNode(
            this.buildContext.getNextId(), constraint, cheeseObjectTypeNode, buildContext);
    alphaNode.attach(buildContext);

    BuildContext buildContext = new BuildContext(kBase, kBase.getReteooBuilder().getIdGenerator());
    buildContext.setTupleMemoryEnabled(false);

    final JoinNode joinNode =
        new JoinNode(
            this.buildContext.getNextId(),
            liaNode,
            alphaNode,
            EmptyBetaConstraints.getInstance(),
            buildContext);
    joinNode.attach(buildContext);

    final QueryTerminalNode queryNode =
        new QueryTerminalNode(
            this.buildContext.getNextId(),
            joinNode,
            query,
            ((QueryImpl) query).getLhs(),
            0,
            buildContext);

    queryNode.attach(buildContext);

    final KnowledgePackageImpl pkg = new KnowledgePackageImpl("com.drools.test");
    pkg.addRule(query);
    ((KnowledgeBaseImpl) kBase).addPackages(Arrays.asList(new InternalKnowledgePackage[] {pkg}));

    KieSession kSession = kBase.newKieSession();
    QueryResults results = kSession.getQueryResults("query-1");

    assertEquals(0, results.size());

    final Cheese stilton1 = new Cheese("stilton", 100);
    final FactHandle handle1 = kSession.insert(stilton1);

    results = kSession.getQueryResults("query-1");

    assertEquals(1, results.size());

    final Cheese cheddar = new Cheese("cheddar", 55);
    kSession.insert(cheddar);

    results = kSession.getQueryResults("query-1");

    assertEquals(1, results.size());

    final Cheese stilton2 = new Cheese("stilton", 5);

    final FactHandle handle2 = kSession.insert(stilton2);

    results = kSession.getQueryResults("query-1");

    assertEquals(2, results.size());

    /**
     * QueryResultsRow result = results.get( 0 ); assertEquals( 1, result.size() ); assertEquals(
     * stilton1, result.get( 0 ) );
     *
     * <p>result = results.get( 1 ); assertEquals( 1, result.size() ); assertEquals( stilton2,
     * result.get( 0 ) );
     */
    int i = 0;
    for (final Iterator<QueryResultsRow> it = results.iterator(); it.hasNext(); ) {
      QueryResultsRow resultRow = it.next();
      if (i == 1) {
        //                assertSame( stilton2, result.g( 0 ) );
      } else {
        //                assertSame( stilton1, result.get( 0 ) );
      }
      i++;
    }

    kSession.delete(handle1);
    results = kSession.getQueryResults("query-1");

    assertEquals(1, results.size());

    kSession.delete(handle2);
    results = kSession.getQueryResults("query-1");

    assertEquals(0, results.size());
  }
  public void testUpdateSinkWithMemory() throws FactException, IntrospectionException {
    // An AlphaNode with memory should not try and repropagate from its source
    // Also it should only update the latest tuple sinky
    RuleBaseConfiguration config = new RuleBaseConfiguration();
    config.setAlphaMemory(true);
    ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase(config);
    BuildContext buildContext =
        new BuildContext(ruleBase, ((ReteooRuleBase) ruleBase).getReteooBuilder().getIdGenerator());
    ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase.newStatefulSession();

    final Rule rule = new Rule("test-rule");
    final PropagationContext context =
        new PropagationContextImpl(0, PropagationContext.ASSERTION, null, null);

    final MockObjectSource source = new MockObjectSource(buildContext.getNextId());

    final FieldExtractor extractor =
        cache.getExtractor(Cheese.class, "type", getClass().getClassLoader());

    final FieldValue field = FieldFactory.getFieldValue("cheddar");

    final Evaluator evaluator = ValueType.OBJECT_TYPE.getEvaluator(Operator.EQUAL);

    final LiteralConstraint constraint = new LiteralConstraint(extractor, evaluator, field);

    buildContext.setAlphaNodeMemoryAllowed(true);
    final AlphaNode alphaNode =
        new AlphaNode(buildContext.getNextId(), constraint, source, buildContext); // has memory

    alphaNode.attach();

    final MockObjectSink sink1 = new MockObjectSink();
    alphaNode.addObjectSink(sink1);

    // Assert a single fact which should be in the AlphaNode memory and also
    // propagated to the
    // the tuple sink
    final Cheese cheese = new Cheese("cheddar", 0);
    final DefaultFactHandle handle1 = new DefaultFactHandle(1, cheese);

    alphaNode.assertObject(handle1, context, workingMemory);

    // Create a fact that should not be propagated, since the alpha node restriction will filter it
    // out
    final Cheese stilton = new Cheese("stilton", 10);
    final DefaultFactHandle handle2 = new DefaultFactHandle(2, stilton);
    // adding handle to the mock source
    source.addFact(handle2);

    alphaNode.assertObject(handle2, context, workingMemory);
    assertLength(1, sink1.getAsserted());

    // Attach a new tuple sink
    final MockObjectSink sink2 = new MockObjectSink();

    // Tell the alphanode to update the new node. Make sure the first sink1
    // is not updated
    // likewise the source should not do anything
    alphaNode.updateSink(sink2, context, workingMemory);

    assertLength(1, sink1.getAsserted());
    assertLength(1, sink2.getAsserted());
    assertEquals(0, source.getUdated());
  }