Example #1
0
  /**
   * @inheritDoc As the accumulate node will always generate a resulting tuple, we must always
   *     destroy it
   */
  public void retractLeftTuple(
      final LeftTuple leftTuple,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this);

    if (leftTuple.getMemory().isStagingMemory()) {
      leftTuple.getMemory().remove(leftTuple);
    } else {
      ((BetaMemory) memory.getBetaMemory()).getLeftTupleMemory().remove(leftTuple);
    }
    leftTuple.setMemory(null);

    final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject();
    if (accctx.getAction() != null) {
      // there is a scheduled activation, we must cancel it
      context.removeInsertAction(accctx.getAction());
    }
    leftTuple.setObject(null);

    removePreviousMatchesForLeftTuple(leftTuple, workingMemory, memory, accctx);

    if (accctx.propagated) {
      // if tuple was previously propagated, retract it and destroy result fact handle
      this.sink.propagateRetractLeftTupleDestroyRightTuple(leftTuple, context, workingMemory);
    } else {
      // if not propagated, just destroy the result fact handle
      // workingMemory.getFactHandleFactory().destroyFactHandle( accctx.result.getFactHandle() );
    }
  }
Example #2
0
  /**
   * @inheritDoc When a new object is asserted into an AccumulateNode, do this:
   *     <p>1. Select all matching tuples from left memory 2. For each matching tuple, call a modify
   *     tuple
   */
  public void assertRightTuple(
      final RightTuple rightTuple,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this);

    memory.betaMemory.getRightTupleMemory().add(rightTuple);

    if (memory.betaMemory.getLeftTupleMemory() == null
        || memory.betaMemory.getLeftTupleMemory().size() == 0) {
      // do nothing here, as we know there are no left tuples at this stage in sequential mode or
      // for a query.
      // unless it's an "Open Query" and thus that will have left memory, so continue as normal
      return;
    }

    this.constraints.updateFromFactHandle(
        memory.betaMemory.getContext(), workingMemory, rightTuple.getFactHandle());

    LeftTupleMemory leftMemory = memory.betaMemory.getLeftTupleMemory();

    FastIterator leftIt = getLeftIterator(leftMemory);

    for (LeftTuple leftTuple = getFirstLeftTuple(rightTuple, leftMemory, context, leftIt);
        leftTuple != null;
        leftTuple = (LeftTuple) leftIt.next(leftTuple)) {
      if (this.constraints.isAllowedCachedRight(memory.betaMemory.getContext(), leftTuple)) {
        final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject();
        addMatch(leftTuple, rightTuple, null, null, workingMemory, memory, accctx, true);
        if (accctx.getAction() == null) {
          // schedule a test to evaluate the constraints, this is an optimisation for sub networks
          // We set Source to LEFT, even though this is a right propagation, because it might end up
          // doing multiple right propagations anyway
          EvaluateResultConstraints action =
              new EvaluateResultConstraints(
                  ActivitySource.LEFT,
                  leftTuple,
                  context,
                  workingMemory,
                  memory,
                  accctx,
                  true,
                  this);
          accctx.setAction(action);
          context.addInsertAction(action);
        }
      }
    }

    this.constraints.resetFactHandle(memory.betaMemory.getContext());
  }
Example #3
0
  /**
   * @inheritDoc When a new tuple is asserted into an AccumulateNode, do this:
   *     <p>1. Select all matching objects from right memory 2. Execute the initialization code
   *     using the tuple + matching objects 3. Execute the accumulation code for each combination of
   *     tuple+object 4. Execute the return code 5. Create a new CalculatedObjectHandle for the
   *     resulting object and add it to the tuple 6. Propagate the tuple
   *     <p>The initialization, accumulation and return codes, in JBRules, are assembled into a
   *     generated method code and called once for the whole match, as you can see below:
   *     <p>Object result = this.accumulator.accumulate( ... );
   */
  public void assertLeftTuple(
      final LeftTuple leftTuple,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {

    final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this);

    AccumulateContext accresult = new AccumulateContext();

    boolean useLeftMemory = true;
    if (!this.tupleMemoryEnabled) {
      // This is a hack, to not add closed DroolsQuery objects
      Object object = ((InternalFactHandle) leftTuple.get(0)).getObject();
      if (!(object instanceof DroolsQuery) || !((DroolsQuery) object).isOpen()) {
        useLeftMemory = false;
      }
    }

    if (useLeftMemory) {
      memory.betaMemory.getLeftTupleMemory().add(leftTuple);
      leftTuple.setObject(accresult);
    }

    accresult.context = this.accumulate.createContext();

    this.accumulate.init(memory.workingMemoryContext, accresult.context, leftTuple, workingMemory);

    this.constraints.updateFromTuple(memory.betaMemory.getContext(), workingMemory, leftTuple);
    RightTupleMemory rightMemory = memory.betaMemory.getRightTupleMemory();

    FastIterator rightIt = getRightIterator(rightMemory);

    for (RightTuple rightTuple = getFirstRightTuple(leftTuple, rightMemory, context, rightIt);
        rightTuple != null;
        rightTuple = (RightTuple) rightIt.next(rightTuple)) {
      InternalFactHandle handle = rightTuple.getFactHandle();
      if (this.constraints.isAllowedCachedLeft(memory.betaMemory.getContext(), handle)) {

        // add a match
        addMatch(
            leftTuple, rightTuple, null, null, workingMemory, memory, accresult, useLeftMemory);
      }
    }

    this.constraints.resetTuple(memory.betaMemory.getContext());

    if (accresult.getAction() == null) {
      evaluateResultConstraints(
          ActivitySource.LEFT, leftTuple, context, workingMemory, memory, accresult, useLeftMemory);
    } // else evaluation is already scheduled, so do nothing
  }
Example #4
0
 private void removePreviousMatchesForRightTuple(
     final RightTuple rightTuple,
     final PropagationContext context,
     final InternalWorkingMemory workingMemory,
     final AccumulateMemory memory,
     final LeftTuple firstChild) {
   for (LeftTuple match = firstChild; match != null; ) {
     final LeftTuple tmp = match.getRightParentNext();
     final LeftTuple parent = match.getLeftParent();
     final AccumulateContext accctx = (AccumulateContext) parent.getObject();
     removeMatch(rightTuple, match, workingMemory, memory, accctx, true);
     if (accctx.getAction() == null) {
       // schedule a test to evaluate the constraints, this is an optimisation for sub networks
       // We set Source to LEFT, even though this is a right propagation, because it might end up
       // doing multiple right propagations anyway
       EvaluateResultConstraints action =
           new EvaluateResultConstraints(
               ActivitySource.LEFT, parent, context, workingMemory, memory, accctx, true, this);
       accctx.setAction(action);
       context.addInsertAction(action);
     }
     match = tmp;
   }
 }
Example #5
0
  /**
   * Evaluate result constraints and propagate assert in case they are true
   *
   * @param leftTuple
   * @param context
   * @param workingMemory
   * @param memory
   * @param accresult
   * @param handle
   */
  public void evaluateResultConstraints(
      final ActivitySource source,
      final LeftTuple leftTuple,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory,
      final AccumulateMemory memory,
      final AccumulateContext accctx,
      final boolean useLeftMemory) {

    // get the actual result
    final Object[] resultArray =
        this.accumulate.getResult(
            memory.workingMemoryContext, accctx.context, leftTuple, workingMemory);
    Object result = this.accumulate.isMultiFunction() ? resultArray : resultArray[0];
    if (result == null) {
      return;
    }

    if (accctx.result == null) {
      final InternalFactHandle handle =
          createResultFactHandle(context, workingMemory, leftTuple, result);

      accctx.result = createRightTuple(handle, this, context);
    } else {
      accctx.result.getFactHandle().setObject(result);
    }

    // First alpha node filters
    boolean isAllowed = result != null;
    for (int i = 0, length = this.resultConstraints.length; isAllowed && i < length; i++) {
      if (!this.resultConstraints[i].isAllowed(
          accctx.result.getFactHandle(), workingMemory, memory.alphaContexts[i])) {
        isAllowed = false;
      }
    }
    if (isAllowed) {
      this.resultBinder.updateFromTuple(memory.resultsContext, workingMemory, leftTuple);
      if (!this.resultBinder.isAllowedCachedLeft(
          memory.resultsContext, accctx.result.getFactHandle())) {
        isAllowed = false;
      }
      this.resultBinder.resetTuple(memory.resultsContext);
    }

    if (accctx.propagated == true) {
      // temporarily break the linked list to avoid wrong interactions
      LeftTuple[] matchings = splitList(leftTuple, accctx, false);
      if (isAllowed) {
        // modify
        if (ActivitySource.LEFT.equals(source)) {
          this.sink.propagateModifyChildLeftTuple(
              leftTuple.getFirstChild(), leftTuple, context, workingMemory, useLeftMemory);
        } else {
          this.sink.propagateModifyChildLeftTuple(
              leftTuple.getFirstChild(), accctx.result, context, workingMemory, useLeftMemory);
        }
      } else {
        // retract
        this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory);
        accctx.propagated = false;
      }
      // restore the matchings list
      restoreList(leftTuple, matchings);
    } else if (isAllowed) {
      // temporarily break the linked list to avoid wrong interactions
      LeftTuple[] matchings = splitList(leftTuple, accctx, false);
      // assert
      this.sink.propagateAssertLeftTuple(
          leftTuple, accctx.result, null, null, context, workingMemory, useLeftMemory);
      accctx.propagated = true;
      // restore the matchings list
      restoreList(leftTuple, matchings);
    }
  }
Example #6
0
  public void modifyRightTuple(
      RightTuple rightTuple, PropagationContext context, InternalWorkingMemory workingMemory) {
    final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this);

    BetaMemory bm = memory.betaMemory;

    // Add and remove to make sure we are in the right bucket and at the end
    // this is needed to fix for indexing and deterministic iteration
    bm.getRightTupleMemory().removeAdd(rightTuple);

    if (bm.getLeftTupleMemory() == null || bm.getLeftTupleMemory().size() == 0) {
      // do nothing here, as we know there are no left tuples at this stage in sequential mode.
      return;
    }

    LeftTuple childLeftTuple = rightTuple.firstChild;

    LeftTupleMemory leftMemory = bm.getLeftTupleMemory();

    FastIterator leftIt = getLeftIterator(leftMemory);

    LeftTuple leftTuple = getFirstLeftTuple(rightTuple, leftMemory, context, leftIt);

    this.constraints.updateFromFactHandle(
        bm.getContext(), workingMemory, rightTuple.getFactHandle());

    // first check our index (for indexed nodes only) hasn't changed and we are returning the same
    // bucket
    // We assume a bucket change if leftTuple == null
    if (childLeftTuple != null
        && leftMemory.isIndexed()
        && !leftIt.isFullIterator()
        && (leftTuple == null
            || (leftTuple.getMemory() != childLeftTuple.getLeftParent().getMemory()))) {
      // our index has changed, so delete all the previous matches
      removePreviousMatchesForRightTuple(
          rightTuple, context, workingMemory, memory, childLeftTuple);
      childLeftTuple = null; // null so the next check will attempt matches for new bucket
    }

    // if LeftTupleMemory is empty, there are no matches to modify
    if (leftTuple != null) {
      if (childLeftTuple == null) {
        // either we are indexed and changed buckets or
        // we had no children before, but there is a bucket to potentially match, so try as normal
        // assert
        for (; leftTuple != null; leftTuple = (LeftTuple) leftIt.next(leftTuple)) {
          if (this.constraints.isAllowedCachedRight(bm.getContext(), leftTuple)) {
            final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject();
            // add a new match
            addMatch(leftTuple, rightTuple, null, null, workingMemory, memory, accctx, true);
            if (accctx.getAction() == null) {
              // schedule a test to evaluate the constraints, this is an optimisation for sub
              // networks
              // We set Source to LEFT, even though this is a right propagation, because it might
              // end up
              // doing multiple right propagations anyway
              EvaluateResultConstraints action =
                  new EvaluateResultConstraints(
                      ActivitySource.LEFT,
                      leftTuple,
                      context,
                      workingMemory,
                      memory,
                      accctx,
                      true,
                      this);
              accctx.setAction(action);
              context.addInsertAction(action);
            }
          }
        }
      } else {
        // in the same bucket, so iterate and compare
        for (; leftTuple != null; leftTuple = (LeftTuple) leftIt.next(leftTuple)) {
          if (this.constraints.isAllowedCachedRight(bm.getContext(), leftTuple)) {
            final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject();
            LeftTuple temp = null;
            if (childLeftTuple != null && childLeftTuple.getLeftParent() == leftTuple) {
              temp = childLeftTuple.getRightParentNext();
              // we must re-add this to ensure deterministic iteration
              childLeftTuple.reAddLeft();
              removeMatch(rightTuple, childLeftTuple, workingMemory, memory, accctx, true);
              childLeftTuple = temp;
            }
            // add a new match
            addMatch(
                leftTuple, rightTuple, null, childLeftTuple, workingMemory, memory, accctx, true);
            if (temp != null) {
              childLeftTuple = temp;
            }
            if (accctx.getAction() == null) {
              // schedule a test to evaluate the constraints, this is an optimisation for sub
              // networks
              // We set Source to LEFT, even though this is a right propagation, because it might
              // end up
              // doing multiple right propagations anyway
              EvaluateResultConstraints action =
                  new EvaluateResultConstraints(
                      ActivitySource.LEFT,
                      leftTuple,
                      context,
                      workingMemory,
                      memory,
                      accctx,
                      true,
                      this);
              accctx.setAction(action);
              context.addInsertAction(action);
            }
          } else if (childLeftTuple != null && childLeftTuple.getLeftParent() == leftTuple) {

            LeftTuple temp = childLeftTuple.getRightParentNext();
            final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject();
            // remove the match
            removeMatch(rightTuple, childLeftTuple, workingMemory, memory, accctx, true);
            if (accctx.getAction() == null) {
              // schedule a test to evaluate the constraints, this is an optimisation for sub
              // networks
              // We set Source to LEFT, even though this is a right propagation, because it might
              // end up
              // doing multiple right propagations anyway
              EvaluateResultConstraints action =
                  new EvaluateResultConstraints(
                      ActivitySource.LEFT,
                      leftTuple,
                      context,
                      workingMemory,
                      memory,
                      accctx,
                      true,
                      this);
              accctx.setAction(action);
              context.addInsertAction(action);
            }

            childLeftTuple = temp;
          }
          // else do nothing, was false before and false now.
        }
      }
    }

    this.constraints.resetFactHandle(bm.getContext());
  }
Example #7
0
  public void modifyLeftTuple(
      LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) {
    final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this);
    final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject();

    BetaMemory bm = memory.betaMemory;

    // Add and remove to make sure we are in the right bucket and at the end
    // this is needed to fix for indexing and deterministic iteration
    bm.getLeftTupleMemory().removeAdd(leftTuple);

    this.constraints.updateFromTuple(bm.getContext(), workingMemory, leftTuple);
    LeftTuple childLeftTuple = getFirstMatch(leftTuple, accctx, false);

    RightTupleMemory rightMemory = bm.getRightTupleMemory();

    FastIterator rightIt = getRightIterator(rightMemory);

    RightTuple rightTuple = getFirstRightTuple(leftTuple, rightMemory, context, rightIt);

    // first check our index (for indexed nodes only) hasn't changed and we are returning the same
    // bucket
    // if rightTuple is null, we assume there was a bucket change and that bucket is empty
    if (childLeftTuple != null
        && rightMemory.isIndexed()
        && !rightIt.isFullIterator()
        && (rightTuple == null
            || (rightTuple.getMemory() != childLeftTuple.getRightParent().getMemory()))) {
      // our index has changed, so delete all the previous matchings
      removePreviousMatchesForLeftTuple(leftTuple, workingMemory, memory, accctx);

      childLeftTuple = null; // null so the next check will attempt matches for new bucket
    }

    // we can't do anything if RightTupleMemory is empty
    if (rightTuple != null) {
      if (childLeftTuple == null) {
        // either we are indexed and changed buckets or
        // we had no children before, but there is a bucket to potentially match, so try as normal
        // assert
        for (; rightTuple != null; rightTuple = (RightTuple) rightIt.next(rightTuple)) {
          final InternalFactHandle handle = rightTuple.getFactHandle();
          if (this.constraints.isAllowedCachedLeft(bm.getContext(), handle)) {
            // add a new match
            addMatch(leftTuple, rightTuple, null, null, workingMemory, memory, accctx, true);
          }
        }
      } else {
        boolean isDirty = false;
        // in the same bucket, so iterate and compare
        for (; rightTuple != null; rightTuple = (RightTuple) rightIt.next(rightTuple)) {
          final InternalFactHandle handle = rightTuple.getFactHandle();

          if (this.constraints.isAllowedCachedLeft(bm.getContext(), handle)) {
            if (childLeftTuple == null || childLeftTuple.getRightParent() != rightTuple) {
              // add a new match
              addMatch(
                  leftTuple, rightTuple, childLeftTuple, null, workingMemory, memory, accctx, true);
            } else {
              // we must re-add this to ensure deterministic iteration
              LeftTuple temp = childLeftTuple.getLeftParentNext();
              childLeftTuple.reAddRight();
              childLeftTuple = temp;
            }
          } else if (childLeftTuple != null && childLeftTuple.getRightParent() == rightTuple) {
            LeftTuple temp = childLeftTuple.getLeftParentNext();
            // remove the match
            removeMatch(rightTuple, childLeftTuple, workingMemory, memory, accctx, false);
            childLeftTuple = temp;
            // the next line means that when a match is removed from the current leftTuple
            // and the accumulate does not support the reverse operation, then the whole
            // result is dirty (since removeMatch above is not recalculating the total)
            // and we need to do this later
            isDirty = !accumulate.supportsReverse();
          }
          // else do nothing, was false before and false now.
        }
        if (isDirty) {
          reaccumulateForLeftTuple(leftTuple, workingMemory, memory, accctx);
        }
      }
    }

    this.constraints.resetTuple(memory.betaMemory.getContext());
    if (accctx.getAction() == null) {
      evaluateResultConstraints(
          ActivitySource.LEFT, leftTuple, context, workingMemory, memory, accctx, true);
    } // else evaluation is already scheduled, so do nothing
  }