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;
 }
  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;
    }
  }