/**
  * PRE: NodeFactory, ConnectionFactory must exist
  *
  * @param reteContainer the ReteNet whose interior is to be mapped.
  */
 public NodeProvisioner(ReteContainer reteContainer) {
   super();
   this.reteContainer = reteContainer;
   this.nodeFactory = reteContainer.getNodeFactory();
   this.connectionFactory = reteContainer.getConnectionFactory();
   this.inputConnector = reteContainer.getInputConnectionFactory();
 }
 /**
  * Internal message delivery method.
  *
  * @pre threads > 0
  */
 private void sendUpdate(
     Address<? extends Receiver> receiver, Direction direction, Tuple updateElement) {
   ReteContainer affectedContainer = receiver.getContainer();
   synchronized (globalTerminationCriteria) {
     long newCriterion =
         affectedContainer.sendUpdateToLocalAddress(receiver, direction, updateElement);
     terminationCriterion(affectedContainer, newCriterion);
   }
 }
 /**
  * Internal message delivery method.
  *
  * @pre threads > 0
  */
 private void sendUpdates(
     Address<? extends Receiver> receiver, Direction direction, Collection<Tuple> updateElements) {
   if (updateElements.isEmpty()) return;
   ReteContainer affectedContainer = receiver.getContainer();
   synchronized (globalTerminationCriteria) {
     long newCriterion =
         affectedContainer.sendUpdatesToLocalAddress(receiver, direction, updateElements);
     terminationCriterion(affectedContainer, newCriterion);
   }
 }
 public synchronized Address<? extends Node> getOrCreateNodeByRecipe(RecipeTraceInfo recipeTrace) {
   final ReteNodeRecipe recipe = recipeTrace.getRecipe();
   Address<? extends Node> result = getNodesByRecipe().get(recipe);
   if (result != null) {
     // NODE ALREADY CONSTRUCTED FOR RECIPE, only needs to add trace
     if (getRecipeTraces().add(recipeTrace)) result.getNodeCache().assignTraceInfo(recipeTrace);
   } else {
     // No node for this recipe object - but equivalent recipes still reusable
     Collection<ReteNodeRecipe> sameClassRecipes = getSameClassRecipes(recipe);
     for (ReteNodeRecipe knownRecipe : sameClassRecipes) {
       if (equivalentRecipes(recipe, knownRecipe)) {
         // FOUND EQUIVALENT RECIPE
         result = getNodesByRecipe().get(knownRecipe);
         getNodesByRecipe().put(recipe, result);
         result.getNodeCache().assignTraceInfo(recipeTrace);
         break;
       }
     }
     if (result == null) {
       // MUST INSTANTIATE NEW NODE FOR RECIPE
       final Node freshNode = instantiateNodeForRecipe(recipeTrace, recipe, sameClassRecipes);
       result = reteContainer.makeAddress(freshNode);
     }
   }
   return result;
 }
  // local version
  public synchronized ProjectionIndexer accessProjectionIndexerOnetime(
      RecipeTraceInfo supplierTrace, TupleMask mask) {
    if (Options.nodeSharingOption != Options.NodeSharingOption.NEVER)
      return accessProjectionIndexer(supplierTrace, mask);

    final Address<? extends Node> supplierAddress = getOrCreateNodeByRecipe(supplierTrace);
    Supplier supplier = (Supplier) reteContainer.resolveLocal(supplierAddress);

    reteContainer.flushUpdates();
    OnetimeIndexer result = new OnetimeIndexer(reteContainer, mask);
    reteContainer.sendConstructionUpdates(
        result, Direction.INSERT, reteContainer.pullContents(supplier));
    reteContainer.flushUpdates();

    return result;
  }
  private Node instantiateNodeForRecipe(
      RecipeTraceInfo recipeTrace,
      final ReteNodeRecipe recipe,
      Collection<ReteNodeRecipe> sameClassRecipes) {
    if (recipe instanceof IndexerRecipe) {

      // INSTANTIATE AND HOOK UP
      // (cannot delay hooking up, because parent determines indexer implementation)
      ensureParents(recipeTrace);
      final ReteNodeRecipe parentRecipe =
          recipeTrace.getParentRecipeTraces().iterator().next().getRecipe();
      final Indexer result =
          nodeFactory.createIndexer(
              reteContainer,
              (IndexerRecipe) recipe,
              asSupplier(
                  (Address<? extends Supplier>)
                      reteContainer.network.getExistingNodeByRecipe(parentRecipe)),
              recipeTrace);

      // REMEMBER
      if (Options.nodeSharingOption != Options.NodeSharingOption.NEVER) {
        getNodesByRecipe().put(recipe, reteContainer.makeAddress(result));
        sameClassRecipes.add(recipe);
      }

      return result;
    } else {

      // INSTANTIATE
      Node result = nodeFactory.createNode(reteContainer, recipe, recipeTrace);

      // REMEMBER
      if (Options.nodeSharingOption == Options.NodeSharingOption.ALL) {
        getNodesByRecipe().put(recipe, reteContainer.makeAddress(result));
        sameClassRecipes.add(recipe);
      }

      // HOOK UP
      // (recursion-tolerant due to this delayed order of initialization)
      ensureParents(recipeTrace);
      if (recipe instanceof InputRecipe) inputConnector.connectInput((InputRecipe) recipe, result);
      else connectionFactory.connectToParents(recipeTrace, result);

      return result;
    }
  }
 // local version
 // TODO remove?
 public synchronized ProjectionIndexer accessProjectionIndexer(
     RecipeTraceInfo supplierTrace, TupleMask mask) {
   final org.eclipse.incquery.runtime.rete.recipes.ProjectionIndexerRecipe
       projectionIndexerRecipe = projectionIndexerRecipe(supplierTrace, mask);
   final UserRequestTrace indexerTrace =
       new UserRequestTrace(projectionIndexerRecipe, supplierTrace);
   final Address<? extends Node> address = getOrCreateNodeByRecipe(indexerTrace);
   return (ProjectionIndexer) reteContainer.resolveLocal(address);
 }
  /**
   * Waits until all rete update operations are settled in all containers. Returns immediately, if
   * no updates are pending.
   *
   * <p>To be called from any user thread.
   */
  public void waitForReteTermination() {
    if (threads > 0) {
      synchronized (globalTerminationCriteria) {
        while (!globalTerminationCriteria.isEmpty()) {
          try {
            globalTerminationCriteria.wait();
          } catch (InterruptedException e) {

          }
        }
      }
    } else headContainer.messageConsumptionSingleThreaded();
  }
 // local, read-only version
 public synchronized ProjectionIndexer peekProjectionIndexer(
     RecipeTraceInfo supplierTrace, TupleMask mask) {
   final Address<? extends Node> address =
       getNodesByRecipe().get(projectionIndexerRecipe(supplierTrace, mask));
   return address == null ? null : (ProjectionIndexer) reteContainer.resolveLocal(address);
 }
 /** The powerful method for accessing any (supplier) Address as a local supplier. */
 public Supplier asSupplier(Address<? extends Supplier> address) {
   if (!reteContainer.isLocal(address)) return accessRemoteSupplier(address);
   else return reteContainer.resolveLocal(address);
 }
 /**
  * Internal message delivery method for single-threaded operation
  *
  * @pre threads == 0
  */
 private void sendUpdateSingleThreaded(
     Address<? extends Receiver> receiver, Direction direction, Tuple updateElement) {
   ReteContainer affectedContainer = receiver.getContainer();
   affectedContainer.sendUpdateToLocalAddressSingleThreaded(receiver, direction, updateElement);
 }
 /** Kills this Network along with all containers and message consumption cycles. */
 public void kill() {
   for (ReteContainer container : containers) {
     container.kill();
   }
   containers.clear();
 }
 protected void propagateUpdate(Direction direction, Tuple updateElement) {
   for (Receiver r : children) reteContainer.sendUpdateInternal(r, direction, updateElement);
 }
 public StandardNode(ReteContainer reteContainer) {
   this.reteContainer = reteContainer;
   this.nodeId = reteContainer.registerNode(this);
   children = new LinkedList<Receiver>();
 }