/**
   * 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);
  }
  /**
   * 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);
    }
  }
 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);
   }
 }