AbstractRecursionPreventingNodeItemVisitor.java

package gov.nist.secauto.metaschema.core.metapath.item.node;

import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition;

public abstract class AbstractRecursionPreventingNodeItemVisitor<CONTEXT, RESULT>
    extends AbstractNodeItemVisitor<CONTEXT, RESULT> {

  @Override
  public RESULT visitAssembly(IAssemblyNodeItem item, CONTEXT context) {
    // only walk new records to avoid looping
    // check if this item's definition is the same as an ancestor's
    return isDecendant(item, item.getDefinition())
        ? defaultResult()
        : super.visitAssembly(item, context);
  }

  /**
   * Determines if the provided node is a descendant of the assembly definition.
   *
   * @param node
   *          the node item to test
   * @param assemblyDefinition
   *          the assembly definition to determine as an ancestor of the node
   * @return {@code true} if the assembly definition is the node's ancestor, or
   *         {@code false} otherwise
   */
  protected boolean isDecendant(IAssemblyNodeItem node, IAssemblyDefinition assemblyDefinition) {
    return node.ancestor()
        .map(ancestor -> {
          boolean retval = false;
          if (ancestor instanceof IAssemblyNodeItem) {
            IAssemblyDefinition ancestorDef = ((IAssemblyNodeItem) ancestor).getDefinition();
            retval = ancestorDef.equals(assemblyDefinition);
          }
          return retval;
        }).anyMatch(value -> value);
  }
}