private boolean hasDescendantNodeInfo(final TreeModel treeModelIn,
                                          final NodeInclusionChecker nodeInclusionChecker,
                                          final boolean ignoreNameFilter,
                                          final ExplorerNode parentNode,
                                          final Collection<ExplorerNode> childNodes,
                                          final LocalMetrics metrics) {

        return metrics.measure("hasDescendantNodeInfo", () -> {
            // See if any of childNodes (or their descendants) have node info in the master model
            boolean hasDescendantNodeInfo = false;
            final Set<ExplorerNode> childrenWithDescendantInfo = treeModelIn.getChildrenWithDescendantInfo(
                    parentNode, childNodes);

            if (NullSafe.hasItems(childrenWithDescendantInfo)) {
                // At least one descendant has node info, but there may be filter/perms limiting what
                // the user can see, or they are in un-opened branches, so we need to walk the full tree
                // to check based on what we can see
                for (final ExplorerNode childNode : childrenWithDescendantInfo) {
                    final boolean isNodeIncluded = metrics.measure("isNodeIncluded", () ->
                            nodeInclusionChecker.isNodeIncluded(ignoreNameFilter, childNode));
                    if (isNodeIncluded) {
                        // This child is included in the filtering and is known to have descendant node info,
                        // so we can mark as found and bail out of this level
                        hasDescendantNodeInfo = true;
                        break;
                    } else {
                        // Not included but its children might be so recurse those nodes known
                        // to have descendant node info
                        final Set<ExplorerNode> grandChildren = treeModelIn.getChildrenWithDescendantInfo(
                                childNode);
                        if (NullSafe.hasItems(grandChildren)) {
                            hasDescendantNodeInfo = hasDescendantNodeInfo(
                                    treeModelIn,
                                    nodeInclusionChecker,
                                    ignoreNameFilter,
                                    childNode,
                                    grandChildren,
                                    metrics);
                        }
                    }
                    if (hasDescendantNodeInfo) {
                        break;
                    }
                }
            }
            return hasDescendantNodeInfo;
        });
    }
@return True if any one of childNodes (or their descendants) has node info and is included
in treeModelOut
stroom-explorer/stroom-explorer-impl/src/main/java/stroom/explorer/impl/ExplorerServiceImpl.java