예제 #1
0
  public void setupJoinNode() {
    buildContext = createContext();

    joinNode =
        (JoinNode)
            BetaNodeBuilder.create(NodeTypeEnums.JoinNode, buildContext)
                .setLeftType(A.class)
                .setBinding("object", "$object")
                .setRightType(B.class)
                .setConstraint("object", "!=", "$object")
                .build();

    sinkNode = new JoinNode();
    sinkNode.setId(1);
    sinkNode.setConstraints(new EmptyBetaConstraints());

    joinNode.addTupleSink(sinkNode);

    wm = (InternalWorkingMemory) buildContext.getRuleBase().newStatefulSession(true);

    bm = (BetaMemory) wm.getNodeMemory(joinNode);

    bm0 = (BetaMemory) wm.getNodeMemory(sinkNode);

    smem = new SegmentMemory(joinNode);
    bm.setSegmentMemory(smem);

    smem0 = new SegmentMemory(sinkNode);
    bm0.setSegmentMemory(smem0);
    smem.add(smem0);
  }
예제 #2
0
  /**
   * When L&R Unlinking is enabled, updateSink() is used to populate a node's memory, but it has to
   * take into account if it's propagating.
   */
  private void updateLRUnlinking(
      final ObjectSink sink,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {

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

    Iterator it = memory.iterator();

    InternalFactHandle ctxHandle = (InternalFactHandle) context.getFactHandle();

    if (!context.isPropagating(this)
        || (context.isPropagating(this) && context.shouldPropagateAll())) {

      for (ObjectEntry entry = (ObjectEntry) it.next();
          entry != null;
          entry = (ObjectEntry) it.next()) {
        // Assert everything
        sink.assertObject((InternalFactHandle) entry.getValue(), context, workingMemory);
      }

    } else {

      for (ObjectEntry entry = (ObjectEntry) it.next();
          entry != null;
          entry = (ObjectEntry) it.next()) {
        InternalFactHandle handle = (InternalFactHandle) entry.getValue();
        // Exclude the current fact propagation
        if (handle.getId() != ctxHandle.getId()) {
          sink.assertObject(handle, context, workingMemory);
        }
      }
    }
  }
예제 #3
0
  /**
   * 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>.
   * @param context
   *             The <code>PropagationContext</code> of the <code>WorkingMemory<code> action.
   * @param workingMemory
   *            the <code>WorkingMemory</code> session.
   */
  public void assertLeftTuple(
      final LeftTuple leftTuple,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    // creating a dummy fact handle to wrap the tuple
    final InternalFactHandle handle =
        workingMemory
            .getFactHandleFactory()
            .newFactHandle(
                leftTuple,
                workingMemory
                    .getObjectTypeConfigurationRegistry()
                    .getObjectTypeConf(context.getEntryPoint(), leftTuple),
                workingMemory,
                null);
    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) {
      final ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory(this);
      // add it to a memory mapping
      memory.put(leftTuple, handle);
    }

    // propagate it
    this.sink.propagateAssertObject(handle, context, workingMemory);
  }
예제 #4
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() );
    }
  }
예제 #5
0
  /**
   * Propagate the <code>FactHandleimpl</code> through the <code>Rete</code> network. All <code>
   * FactHandleImpl</code> should be remembered in the node memory, so that later runtime rule
   * attachmnents can have the matched facts propagated to them.
   *
   * @param factHandle The fact handle.
   * @param object The object to assert.
   * @param workingMemory The working memory session.
   */
  public void assertObject(
      final InternalFactHandle factHandle,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {

    if (objectMemoryEnabled && !(queryNode && !((DroolsQuery) factHandle.getObject()).isOpen())) {
      final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this);
      memory.add(factHandle, false);
    }

    if (compiledNetwork != null) {
      compiledNetwork.assertObject(factHandle, context, workingMemory);
    } else {

      context.setCurrentPropagatingOTN(this);
      this.sink.propagateAssertObject(factHandle, context, workingMemory);
    }

    if (this.objectType.isEvent()
        && this.expirationOffset >= 0
        && this.expirationOffset != Long.MAX_VALUE) {
      // schedule expiration
      WorkingMemoryReteExpireAction expire = new WorkingMemoryReteExpireAction(factHandle, this);
      TimerService clock = workingMemory.getTimerService();

      long nextTimestamp =
          Math.max(
              clock.getCurrentTime() + this.expirationOffset,
              ((EventFactHandle) factHandle).getStartTimestamp() + this.expirationOffset);
      JobContext jobctx = new ExpireJobContext(expire, workingMemory);
      JobHandle handle =
          clock.scheduleJob(job, jobctx, new PointInTimeTrigger(nextTimestamp, null, null));
      jobctx.setJobHandle(handle);
    }
  }
  /**
   * Propagate the <code>FactHandleimpl</code> through the <code>Rete</code> network. All <code>
   * FactHandleImpl</code> should be remembered in the node memory, so that later runtime rule
   * attachmnents can have the matched facts propagated to them.
   *
   * @param factHandle The fact handle.
   * @param object The object to assert.
   * @param workingMemory The working memory session.
   */
  public void assertObject(
      final InternalFactHandle factHandle,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    if (context.getType() == PropagationContext.MODIFICATION
        && this.skipOnModify
        && context.getDormantActivations() == 0) {
      // we do this after the shadowproxy update, just so that its up to date for the future
      return;
    }

    if (this.objectMemoryEnabled) {
      final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this);
      memory.add(factHandle, false);
    }
    this.sink.propagateAssertObject(factHandle, context, workingMemory);

    if (this.expirationOffset >= 0) {
      // schedule expiration
      WorkingMemoryReteExpireAction expire = new WorkingMemoryReteExpireAction(factHandle, this);
      TimerService clock = workingMemory.getTimerService();

      long nextTimestamp = clock.getCurrentTime() + this.expirationOffset;
      JobContext jobctx = new ExpireJobContext(expire, workingMemory);
      JobHandle handle = clock.scheduleJob(job, jobctx, new PointInTimeTrigger(nextTimestamp));
      jobctx.setJobHandle(handle);
    }
  }
  /**
   * Retract the <code>FactHandleimpl</code> from the <code>Rete</code> network. Also remove the
   * <code>FactHandleImpl</code> from the node memory.
   *
   * @param rightTuple The fact handle.
   * @param object The object to assert.
   * @param workingMemory The working memory session.
   */
  public void retractObject(
      final InternalFactHandle factHandle,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {

    if (context.getType() == PropagationContext.MODIFICATION
        && this.skipOnModify
        && context.getDormantActivations() == 0) {
      return;
    }

    if (this.objectMemoryEnabled) {
      final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this);
      memory.remove(factHandle);
    }

    for (RightTuple rightTuple = factHandle.getRightTuple();
        rightTuple != null;
        rightTuple = (RightTuple) rightTuple.getHandleNext()) {
      rightTuple.getRightTupleSink().retractRightTuple(rightTuple, context, workingMemory);
    }
    factHandle.setRightTuple(null);

    for (LeftTuple leftTuple = factHandle.getLeftTuple();
        leftTuple != null;
        leftTuple = (LeftTuple) leftTuple.getLeftParentNext()) {
      leftTuple.getLeftTupleSink().retractLeftTuple(leftTuple, context, workingMemory);
    }
    factHandle.setLeftTuple(null);
  }
예제 #8
0
  protected void doRemove(
      final RuleRemovalContext context,
      final ReteooBuilder builder,
      final BaseNode node,
      final InternalWorkingMemory[] workingMemories) {
    if (!node.isInUse()) {
      removeObjectSink((ObjectSink) node);
    }

    if (!this.isInUse()) {
      for (InternalWorkingMemory workingMemory : workingMemories) {
        ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory(this);

        Iterator it = memory.iterator();
        for (ObjectEntry entry = (ObjectEntry) it.next();
            entry != null;
            entry = (ObjectEntry) it.next()) {
          LeftTuple leftTuple = (LeftTuple) entry.getKey();
          leftTuple.unlinkFromLeftParent();
          leftTuple.unlinkFromRightParent();
        }
        workingMemory.clearNodeMemory(this);
      }
    }
    this.tupleSource.remove(context, builder, this, workingMemories);
  }
예제 #9
0
 /**
  * OTN needs to override remove to avoid releasing the node ID, since OTN are never removed from
  * the rulebase in the current implementation
  */
 protected void doRemove(
     final RuleRemovalContext context,
     final ReteooBuilder builder,
     final BaseNode node,
     final InternalWorkingMemory[] workingMemories) {
   if (context.getCleanupAdapter() != null) {
     for (InternalWorkingMemory workingMemory : workingMemories) {
       CleanupAdapter adapter = context.getCleanupAdapter();
       final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this);
       Iterator it = memory.iterator();
       for (ObjectEntry entry = (ObjectEntry) it.next();
           entry != null;
           entry = (ObjectEntry) it.next()) {
         InternalFactHandle handle = (InternalFactHandle) entry.getValue();
         for (LeftTuple leftTuple = handle.getFirstLeftTuple();
             leftTuple != null;
             leftTuple = leftTuple.getLeftParentNext()) {
           adapter.cleanUp(leftTuple, workingMemory);
         }
       }
     }
     context.setCleanupAdapter(null);
   }
   if (!node.isInUse()) {
     removeObjectSink((ObjectSink) node);
   }
 }
예제 #10
0
  public void updateSink(
      final ObjectSink sink,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    // @todo
    // JBRULES-612: the cache MUST be invalidated when a new node type is added to the network, so
    // iterate and reset all caches.
    final ObjectTypeNode node = (ObjectTypeNode) sink;

    final ObjectType newObjectType = node.getObjectType();

    InternalWorkingMemoryEntryPoint wmEntryPoint =
        (InternalWorkingMemoryEntryPoint)
            workingMemory.getWorkingMemoryEntryPoint(this.entryPoint.getEntryPointId());

    for (ObjectTypeConf objectTypeConf :
        wmEntryPoint.getObjectTypeConfigurationRegistry().values()) {
      if (newObjectType.isAssignableFrom(
          objectTypeConf.getConcreteObjectTypeNode().getObjectType())) {
        objectTypeConf.resetCache();
        ObjectTypeNode sourceNode = objectTypeConf.getConcreteObjectTypeNode();
        Iterator it =
            ((ObjectTypeNodeMemory) workingMemory.getNodeMemory(sourceNode)).memory.iterator();
        for (ObjectEntry entry = (ObjectEntry) it.next();
            entry != null;
            entry = (ObjectEntry) it.next()) {
          sink.assertObject((InternalFactHandle) entry.getValue(), context, workingMemory);
        }
      }
    }
  }
 public void updateSink(
     final ObjectSink sink,
     final PropagationContext context,
     final InternalWorkingMemory workingMemory) {
   final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this);
   Iterator it = memory.iterator();
   for (ObjectEntry entry = (ObjectEntry) it.next();
       entry != null;
       entry = (ObjectEntry) it.next()) {
     sink.assertObject((InternalFactHandle) entry.getValue(), context, workingMemory);
   }
 }
예제 #12
0
  public void modifyLeftTuple(
      LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) {
    final ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory(this);
    // add it to a memory mapping
    InternalFactHandle handle = (InternalFactHandle) memory.get(leftTuple);

    // propagate it
    for (RightTuple rightTuple = handle.getFirstRightTuple();
        rightTuple != null;
        rightTuple = (RightTuple) rightTuple.getHandleNext()) {
      rightTuple.getRightTupleSink().modifyRightTuple(rightTuple, context, workingMemory);
    }
  }
예제 #13
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());
  }
예제 #14
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
  }
예제 #15
0
  /**
   * Retract the
   * <code>ReteTuple<code>, any resulting propagated joins are also retracted.
   *
   * @param leftTuple
   *            The tuple being retracted
   * @param context
   *            The <code>PropagationContext</code>
   * @param workingMemory
   *            The working memory session.
   */
  public void retractLeftTuple(
      final LeftTuple leftTuple,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    RightTuple blocker = leftTuple.getBlocker();
    final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this);
    if (blocker != null) {
      this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory);

      blocker.removeBlocked(leftTuple);
    } else {
      memory.getLeftTupleMemory().remove(leftTuple);
    }
  }
예제 #16
0
  /**
   * Retract the <code>FactHandleImpl</code>. If the handle has any <code>ReteTuple</code> matches
   * and those tuples now have no other match, retract tuple
   *
   * @param handle the <codeFactHandleImpl</code> being retracted
   * @param context The <code>PropagationContext</code>
   * @param workingMemory The working memory session.
   */
  public void retractRightTuple(
      final RightTuple rightTuple,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this);

    FastIterator it = memory.getRightTupleMemory().fastIterator();
    final RightTuple rootBlocker = (RightTuple) it.next(rightTuple);

    memory.getRightTupleMemory().remove(rightTuple);

    if (rightTuple.getBlocked() == null) {
      return;
    }

    for (LeftTuple leftTuple = (LeftTuple) rightTuple.getBlocked(); leftTuple != null; ) {
      LeftTuple temp = leftTuple.getBlockedNext();

      leftTuple.setBlocker(null);
      leftTuple.setBlockedPrevious(null);
      leftTuple.setBlockedNext(null);

      this.constraints.updateFromTuple(memory.getContext(), workingMemory, leftTuple);

      // we know that older tuples have been checked so continue previously
      for (RightTuple newBlocker = rootBlocker;
          newBlocker != null;
          newBlocker = (RightTuple) it.next(newBlocker)) {
        if (this.constraints.isAllowedCachedLeft(memory.getContext(), newBlocker.getFactHandle())) {
          leftTuple.setBlocker(newBlocker);
          newBlocker.addBlocked(leftTuple);

          break;
        }
      }

      if (leftTuple.getBlocker() == null) {
        // was previous blocked and not in memory, so add
        memory.getLeftTupleMemory().add(leftTuple);

        this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory);
      }

      leftTuple = temp;
    }
    rightTuple.nullBlocked();
    this.constraints.resetTuple(memory.getContext());
  }
예제 #17
0
  public void updateSink(
      final ObjectSink sink,
      final PropagationContext context,
      final InternalWorkingMemory 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);
    }
  }
예제 #18
0
  /**
   * Assert a new <code>ReteTuple</code> from the left input. It iterates over the right <code>
   * FactHandleImpl</code>'s and if any match is found, a copy of the <code>ReteTuple</code> is made
   * and propagated.
   *
   * @param tuple The <code>Tuple</code> being asserted.
   * @param context The <code>PropagationContext</code>
   * @param workingMemory The working memory session.
   */
  public void assertLeftTuple(
      final LeftTuple leftTuple,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this);
    RightTupleMemory rightMemory = memory.getRightTupleMemory();

    ContextEntry[] contextEntry = memory.getContext();

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

    this.constraints.updateFromTuple(contextEntry, workingMemory, leftTuple);

    FastIterator it = getRightIterator(rightMemory);

    for (RightTuple rightTuple = getFirstRightTuple(leftTuple, rightMemory, context, it);
        rightTuple != null;
        rightTuple = (RightTuple) it.next(rightTuple)) {
      if (this.constraints.isAllowedCachedLeft(contextEntry, rightTuple.getFactHandle())) {

        leftTuple.setBlocker(rightTuple);
        if (useLeftMemory) {
          rightTuple.addBlocked(leftTuple);
        }

        break;
      }
    }

    this.constraints.resetTuple(contextEntry);

    if (leftTuple.getBlocker() != null) {
      // tuple is not blocked to propagate
      this.sink.propagateAssertLeftTuple(leftTuple, context, workingMemory, useLeftMemory);
    } else if (useLeftMemory) {
      // LeftTuple is not blocked, so add to memory so other RightTuples can match
      memory.getLeftTupleMemory().add(leftTuple);
    }
  }
예제 #19
0
  public void assertLeftTuple(
      LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) {
    // the next call makes sure this node's memory is initialised
    workingMemory.getNodeMemory(this);

    InternalFactHandle handle = createFactHandle(context, workingMemory, leftTuple);

    DroolsQuery queryObject = createDroolsQuery(leftTuple, handle, workingMemory);

    QueryInsertAction action = new QueryInsertAction(context, handle, leftTuple, this);
    queryObject.setAction(
        action); // this is necessary as queries can be re-entrant, so we can check this before
    // re-sheduling
    // another action in the modify section. Make sure it's nulled after the action is done
    // i.e. scheduling an insert and then an update, before the insert is executed
    context.getQueue1().addFirst(action);
  }
  public static void readFactHandles(MarshallerReaderContext context, ObjectStore objectStore)
      throws IOException, ClassNotFoundException {
    ObjectInputStream stream = context.stream;
    InternalWorkingMemory wm = context.wm;

    int size = stream.readInt();

    // load the handles
    InternalFactHandle[] handles = new InternalFactHandle[size];
    for (int i = 0; i < size; i++) {
      InternalFactHandle handle = readFactHandle(context);

      context.handles.put(handle.getId(), handle);
      handles[i] = handle;

      if (handle.getObject() != null) {
        objectStore.addHandle(handle, handle.getObject());
      }

      readRightTuples(handle, context);
    }

    readLeftTuples(context); // object store

    if (stream.readBoolean()) {
      readLeftTuples(context); // activation fact handles
    }

    // add handles to object type nodes
    for (InternalFactHandle factHandle : handles) {
      Object object = factHandle.getObject();

      EntryPoint ep =
          ((InternalWorkingMemoryEntryPoint) factHandle.getEntryPoint()).getEntryPoint();

      ObjectTypeConf typeConf =
          ((InternalWorkingMemoryEntryPoint) factHandle.getEntryPoint())
              .getObjectTypeConfigurationRegistry()
              .getObjectTypeConf(ep, object);
      ObjectTypeNode[] cachedNodes = typeConf.getObjectTypeNodes();
      for (int i = 0, length = cachedNodes.length; i < length; i++) {
        ObjectHashSet set = (ObjectHashSet) wm.getNodeMemory(cachedNodes[i]);
        set.add(factHandle, false);
      }
    }
  }
예제 #21
0
  /** Updates the given sink propagating all previously propagated tuples to it */
  public void updateSink(
      final LeftTupleSink sink,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this);
    Iterator it = memory.getRightTupleMemory().iterator();

    // Relies on the fact that any propagated LeftTuples are blocked, but due to lazy blocking
    // they will only be blocked once. So we can iterate the right memory to find the left tuples to
    // propagate
    for (RightTuple rightTuple = (RightTuple) it.next();
        rightTuple != null;
        rightTuple = (RightTuple) it.next()) {
      LeftTuple leftTuple = rightTuple.getBlocked();
      while (leftTuple != null) {
        sink.assertLeftTuple(sink.createLeftTuple(leftTuple, sink, true), context, workingMemory);
        leftTuple = leftTuple.getBlockedNext();
      }
    }
  }
예제 #22
0
  public void updateSink(
      final ObjectSink sink,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    if (lrUnlinkingEnabled) {
      // Update sink taking into account L&R unlinking peculiarities
      updateLRUnlinking(sink, context, workingMemory);

    } else {
      // Regular updateSink
      final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this);
      Iterator it = memory.iterator();

      for (ObjectEntry entry = (ObjectEntry) it.next();
          entry != null;
          entry = (ObjectEntry) it.next()) {
        sink.assertObject((InternalFactHandle) entry.getValue(), context, workingMemory);
      }
    }
  }
예제 #23
0
  /** @inheritDoc If an object is retract, call modify tuple for each tuple match. */
  public void retractRightTuple(
      final RightTuple rightTuple,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this);
    final InternalFactHandle origin = (InternalFactHandle) context.getFactHandleOrigin();
    if (context.getType() == PropagationContext.EXPIRATION) {
      ((PropagationContextImpl) context).setFactHandle(null);
    }

    BetaMemory bm = memory.getBetaMemory();

    if (isUnlinkingEnabled()) {

      StagedRightTuples stagedRightTuples = bm.getStagedRightTuples();
      switch (rightTuple.getStagedType()) {
          // handle clash with already staged entries
        case LeftTuple.INSERT:
          stagedRightTuples.removeInsert(rightTuple);
          break;
        case LeftTuple.UPDATE:
          stagedRightTuples.removeUpdate(rightTuple);
          break;
      }
      stagedRightTuples.addDelete(rightTuple);
      if (bm.getDecAndGetCounter() == 0 && !isRightInputIsRiaNode()) {
        bm.unlinkNode(workingMemory);
      }
      return;
    }

    bm.getRightTupleMemory().remove(rightTuple);

    removePreviousMatchesForRightTuple(
        rightTuple, context, workingMemory, memory, rightTuple.firstChild);

    if (context.getType() == PropagationContext.EXPIRATION) {
      ((PropagationContextImpl) context).setFactHandle(origin);
    }
  }
예제 #24
0
  /** Retracts the corresponding tuple by retrieving and retracting the fact created for it */
  public void retractLeftTuple(
      final LeftTuple tuple,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    final ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory(this);
    // retrieve handle from memory
    final InternalFactHandle factHandle = (InternalFactHandle) memory.remove(tuple);

    for (RightTuple rightTuple = factHandle.getFirstRightTuple();
        rightTuple != null;
        rightTuple = (RightTuple) rightTuple.getHandleNext()) {
      rightTuple.getRightTupleSink().retractRightTuple(rightTuple, context, workingMemory);
    }
    factHandle.clearRightTuples();

    for (LeftTuple leftTuple = factHandle.getLastLeftTuple();
        leftTuple != null;
        leftTuple = (LeftTuple) leftTuple.getLeftParentNext()) {
      leftTuple.getLeftTupleSink().retractLeftTuple(leftTuple, context, workingMemory);
    }
    factHandle.clearLeftTuples();
  }
예제 #25
0
  /**
   * Assert a new <code>FactHandleImpl</code> from the right input. If it matches any left
   * ReteTuple's that had no matches before, propagate tuple as an assertion.
   *
   * @param factHandle The <code>FactHandleImpl</code> being asserted.
   * @param context The <code>PropagationContext</code>
   * @param workingMemory The working memory session.
   */
  public void assertObject(
      final InternalFactHandle factHandle,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {

    final RightTuple rightTuple = createRightTuple(factHandle, this, context);

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

    memory.getRightTupleMemory().add(rightTuple);

    if (memory.getLeftTupleMemory() == null || memory.getLeftTupleMemory().size() == 0) {
      // do nothing here, as no left memory
      return;
    }

    this.constraints.updateFromFactHandle(memory.getContext(), workingMemory, factHandle);
    LeftTupleMemory leftMemory = memory.getLeftTupleMemory();
    FastIterator it = getLeftIterator(leftMemory);
    for (LeftTuple leftTuple = getFirstLeftTuple(rightTuple, leftMemory, context, it);
        leftTuple != null; ) {
      // preserve next now, in case we remove this leftTuple
      LeftTuple temp = (LeftTuple) it.next(leftTuple);

      // we know that only unblocked LeftTuples are  still in the memory
      if (this.constraints.isAllowedCachedRight(memory.getContext(), leftTuple)) {
        leftTuple.setBlocker(rightTuple);
        rightTuple.addBlocked(leftTuple);

        memory.getLeftTupleMemory().remove(leftTuple);

        this.sink.propagateAssertLeftTuple(leftTuple, context, workingMemory, true);
      }

      leftTuple = temp;
    }

    this.constraints.resetFactHandle(memory.getContext());
  }
예제 #26
0
  public void updateSink(
      final LeftTupleSink sink,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this);

    final Iterator tupleIter = memory.betaMemory.getLeftTupleMemory().iterator();
    for (LeftTuple leftTuple = (LeftTuple) tupleIter.next();
        leftTuple != null;
        leftTuple = (LeftTuple) tupleIter.next()) {
      AccumulateContext accctx = (AccumulateContext) leftTuple.getObject();
      if (accctx.propagated) {
        // temporarily break the linked list to avoid wrong interactions
        LeftTuple[] matchings = splitList(leftTuple, accctx, true);
        sink.assertLeftTuple(
            sink.createLeftTuple(leftTuple, accctx.result, null, null, sink, true),
            context,
            workingMemory);
        restoreList(leftTuple, matchings);
      }
    }
  }
예제 #27
0
  /**
   * Retract the <code>FactHandleimpl</code> from the <code>Rete</code> network. Also remove the
   * <code>FactHandleImpl</code> from the node memory.
   *
   * @param rightTuple The fact handle.
   * @param object The object to assert.
   * @param workingMemory The working memory session.
   */
  public void retractObject(
      final InternalFactHandle factHandle,
      final PropagationContext context,
      final InternalWorkingMemory workingMemory) {
    if (objectMemoryEnabled && !(queryNode && !((DroolsQuery) factHandle.getObject()).isOpen())) {
      final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this);
      memory.remove(factHandle);
    }

    for (RightTuple rightTuple = factHandle.getFirstRightTuple();
        rightTuple != null;
        rightTuple = (RightTuple) rightTuple.getHandleNext()) {
      rightTuple.getRightTupleSink().retractRightTuple(rightTuple, context, workingMemory);
    }
    factHandle.clearRightTuples();

    for (LeftTuple leftTuple = factHandle.getFirstLeftTuple();
        leftTuple != null;
        leftTuple = (LeftTuple) leftTuple.getLeftParentNext()) {
      leftTuple.getLeftTupleSink().retractLeftTuple(leftTuple, context, workingMemory);
    }
    factHandle.clearLeftTuples();
  }
예제 #28
0
  protected void doRemove(
      final RuleRemovalContext context,
      final ReteooBuilder builder,
      final BaseNode node,
      final InternalWorkingMemory[] workingMemories) {
    if (!node.isInUse()) {
      removeTupleSink((LeftTupleSink) node);
    }
    if (!this.isInUse() || context.getCleanupAdapter() != null) {
      for (InternalWorkingMemory workingMemory : workingMemories) {
        BetaMemory memory;
        Object object = workingMemory.getNodeMemory(this);

        // handle special cases for Accumulate to make sure they tidy up their specific data
        // like destroying the local FactHandles
        if (object instanceof AccumulateMemory) {
          memory = ((AccumulateMemory) object).betaMemory;
        } else {
          memory = (BetaMemory) object;
        }

        FastIterator it = memory.getLeftTupleMemory().fullFastIterator();
        for (LeftTuple leftTuple = getFirstLeftTuple(memory.getLeftTupleMemory(), it);
            leftTuple != null; ) {
          LeftTuple tmp = (LeftTuple) it.next(leftTuple);
          if (context.getCleanupAdapter() != null) {
            LeftTuple child;
            while ((child = leftTuple.getFirstChild()) != null) {
              if (child.getLeftTupleSink() == this) {
                // this is a match tuple on collect and accumulate nodes, so just unlink it
                child.unlinkFromLeftParent();
                child.unlinkFromRightParent();
              } else {
                // the cleanupAdapter will take care of the unlinking
                context.getCleanupAdapter().cleanUp(child, workingMemory);
              }
            }
          }
          memory.getLeftTupleMemory().remove(leftTuple);
          leftTuple.unlinkFromLeftParent();
          leftTuple.unlinkFromRightParent();
          leftTuple = tmp;
        }

        // handle special cases for Accumulate to make sure they tidy up their specific data
        // like destroying the local FactHandles
        if (object instanceof AccumulateMemory) {
          ((AccumulateNode) this).doRemove(workingMemory, (AccumulateMemory) object);
        }

        if (!this.isInUse()) {
          it = memory.getRightTupleMemory().fullFastIterator();
          for (RightTuple rightTuple = getFirstRightTuple(memory.getRightTupleMemory(), it);
              rightTuple != null; ) {
            RightTuple tmp = (RightTuple) it.next(rightTuple);
            if (rightTuple.getBlocked() != null) {
              // special case for a not, so unlink left tuple from here, as they aren't in the left
              // memory
              for (LeftTuple leftTuple = rightTuple.getBlocked(); leftTuple != null; ) {
                LeftTuple temp = leftTuple.getBlockedNext();

                leftTuple.setBlocker(null);
                leftTuple.setBlockedPrevious(null);
                leftTuple.setBlockedNext(null);
                leftTuple.unlinkFromLeftParent();
                leftTuple = temp;
              }
            }
            memory.getRightTupleMemory().remove(rightTuple);
            rightTuple.unlinkFromRightParent();
            rightTuple = tmp;
          }
          workingMemory.clearNodeMemory(this);
        }
      }
      context.setCleanupAdapter(null);
    }
    this.rightInput.remove(context, builder, this, workingMemories);
    this.leftInput.remove(context, builder, this, workingMemories);
  }
예제 #29
0
  public void modifyRightTuple(
      RightTuple rightTuple, PropagationContext context, InternalWorkingMemory workingMemory) {
    final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this);

    if (memory.getLeftTupleMemory() == null
        || (memory.getLeftTupleMemory().size() == 0 && rightTuple.getBlocked() == null)) {
      // do nothing here, as we know there are no left tuples

      // normally do this at the end, but as we are exiting early, make sure the buckets are still
      // correct.
      memory.getRightTupleMemory().removeAdd(rightTuple);
      return;
    }

    // TODO: wtd with behaviours?
    //        if ( !behavior.assertRightTuple( memory.getBehaviorContext(),
    //                                         rightTuple,
    //                                         workingMemory ) ) {
    //            // destroy right tuple
    //            rightTuple.unlinkFromRightParent();
    //            return;
    //        }
    this.constraints.updateFromFactHandle(
        memory.getContext(), workingMemory, rightTuple.getFactHandle());

    LeftTupleMemory leftMemory = memory.getLeftTupleMemory();
    FastIterator leftIt = getLeftIterator(leftMemory);
    LeftTuple firstLeftTuple = getFirstLeftTuple(rightTuple, leftMemory, context, leftIt);

    LeftTuple firstBlocked = rightTuple.getBlocked();
    // we now have  reference to the first Blocked, so null it in the rightTuple itself, so we can
    // rebuild
    rightTuple.nullBlocked();

    // first process non-blocked tuples, as we know only those ones are in the left memory.
    for (LeftTuple leftTuple = firstLeftTuple; leftTuple != null; ) {
      // preserve next now, in case we remove this leftTuple
      LeftTuple temp = (LeftTuple) leftIt.next(leftTuple);

      // we know that only unblocked LeftTuples are  still in the memory
      if (this.constraints.isAllowedCachedRight(memory.getContext(), leftTuple)) {
        leftTuple.setBlocker(rightTuple);
        rightTuple.addBlocked(leftTuple);

        // this is now blocked so remove from memory
        leftMemory.remove(leftTuple);

        // subclasses like ForallNotNode might override this propagation
        this.sink.propagateAssertLeftTuple(leftTuple, context, workingMemory, true);
      }

      leftTuple = temp;
    }

    if (firstBlocked != null) {
      // now process existing blocks, we only process existing and not new from above loop
      FastIterator rightIt = getRightIterator(memory.getRightTupleMemory());
      RightTuple rootBlocker = (RightTuple) rightIt.next(rightTuple);

      RightTupleList list = rightTuple.getMemory();

      // we must do this after we have the next in memory
      // We add to the end to give an opportunity to re-match if in same bucket
      memory.getRightTupleMemory().removeAdd(rightTuple);

      if (rootBlocker == null && list == rightTuple.getMemory()) {
        // we are at the end of the list, but still in same bucket, so set to self, to give self a
        // chance to rematch
        rootBlocker = rightTuple;
      }

      // iterate all the existing previous blocked LeftTuples
      for (LeftTuple leftTuple = (LeftTuple) firstBlocked; leftTuple != null; ) {
        LeftTuple temp = leftTuple.getBlockedNext();

        leftTuple.setBlockedPrevious(null); // must null these as we are re-adding them to the list
        leftTuple.setBlockedNext(null);

        leftTuple.setBlocker(null);

        this.constraints.updateFromTuple(memory.getContext(), workingMemory, leftTuple);

        // we know that older tuples have been checked so continue next
        for (RightTuple newBlocker = rootBlocker;
            newBlocker != null;
            newBlocker = (RightTuple) rightIt.next(newBlocker)) {
          if (this.constraints.isAllowedCachedLeft(
              memory.getContext(), newBlocker.getFactHandle())) {
            leftTuple.setBlocker(newBlocker);
            newBlocker.addBlocked(leftTuple);

            break;
          }
        }

        if (leftTuple.getBlocker() == null) {
          // was previous blocked and not in memory, so add
          memory.getLeftTupleMemory().add(leftTuple);

          // subclasses like ForallNotNode might override this propagation
          this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory);
        }

        leftTuple = temp;
      }
    } else {
      // we had to do this at the end, rather than beginning as this 'if' block needs the next
      // memory tuple
      memory.getRightTupleMemory().removeAdd(rightTuple);
    }

    this.constraints.resetFactHandle(memory.getContext());
    this.constraints.resetTuple(memory.getContext());
  }
예제 #30
0
  public void modifyLeftTuple(
      LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) {
    final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this);
    RightTupleMemory rightMemory = memory.getRightTupleMemory();

    FastIterator rightIt = getRightIterator(rightMemory);
    RightTuple firstRightTuple = getFirstRightTuple(leftTuple, rightMemory, context, rightIt);

    // If in memory, remove it, because we'll need to add it anyway if it's not blocked, to ensure
    // iteration order
    RightTuple blocker = leftTuple.getBlocker();
    if (blocker == null) {
      memory.getLeftTupleMemory().remove(leftTuple);
    } else {
      // check if we changed bucket
      if (rightMemory.isIndexed() && !rightIt.isFullIterator()) {
        // if newRightTuple is null, we assume there was a bucket change and that bucket is empty
        if (firstRightTuple == null || firstRightTuple.getMemory() != blocker.getMemory()) {
          // we changed bucket, so blocker no longer blocks
          blocker.removeBlocked(leftTuple);
          leftTuple.setBlocker(null);
          leftTuple.setBlockedPrevious(null);
          leftTuple.setBlockedNext(null);
          blocker = null;
        }
      }
    }

    this.constraints.updateFromTuple(memory.getContext(), workingMemory, leftTuple);

    // if we where not blocked before (or changed buckets), or the previous blocker no longer
    // blocks, then find the next blocker
    if (blocker == null
        || !this.constraints.isAllowedCachedLeft(memory.getContext(), blocker.getFactHandle())) {

      if (blocker != null) {
        // remove previous blocker if it exists, as we know it doesn't block any more
        blocker.removeBlocked(leftTuple);
        leftTuple.setBlocker(null);
        leftTuple.setBlockedPrevious(null);
        leftTuple.setBlockedNext(null);
      }

      FastIterator it = memory.getRightTupleMemory().fastIterator();

      // find first blocker, because it's a modify, we need to start from the beginning again
      for (RightTuple newBlocker = firstRightTuple;
          newBlocker != null;
          newBlocker = (RightTuple) rightIt.next(newBlocker)) {
        if (this.constraints.isAllowedCachedLeft(memory.getContext(), newBlocker.getFactHandle())) {
          leftTuple.setBlocker(newBlocker);
          newBlocker.addBlocked(leftTuple);

          break;
        }
      }
    }

    if (leftTuple.getBlocker() == null) {
      // not blocked
      memory
          .getLeftTupleMemory()
          .add(leftTuple); // add to memory so other fact handles can attempt to match

      if (leftTuple.getFirstChild() != null) {
        // with previous children, retract
        this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory);
      }
      // with no previous children. do nothing.
    } else if (leftTuple.getFirstChild() == null) {
      // blocked, with no previous children, assert
      this.sink.propagateAssertLeftTuple(leftTuple, context, workingMemory, true);
    } else {
      // blocked, with previous children, modify
      this.sink.propagateModifyChildLeftTuple(leftTuple, context, workingMemory, true);
    }

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