/* * Copyright 2017 Adobe. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.adobe.acs.commons.util.visitors; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.function.BiConsumer; import java.util.function.Function; import org.apache.jackrabbit.spi.commons.iterator.Iterators; import org.apache.sling.api.resource.Resource; public class SimpleFilteringResourceVisitor { public static enum TraversalMode { DEPTH, BREADTH }; TraversalMode mode = TraversalMode.BREADTH; BiConsumer<Map.Entry<String, Object>, Integer> propertyVisitor = null; BiConsumer<Resource, Integer> resourceVisitor = null; BiConsumer<Resource, Integer> leafVisitor = null; Queue<Resource> currentLevel = new LinkedList<>(); Queue<Resource> nextLevel = new LinkedList<>(); Function<String, Boolean> propertyFilter = s -> true; Function<Resource, Boolean> traversalFilter = r -> true; public SimpleFilteringResourceVisitor() { } public void setPropertyFilter(Function<String, Boolean> filter) { propertyFilter = filter; } public final void setTraversalFilter(Function<Resource, Boolean> filter) { traversalFilter = filter; } public final void setResourceVisitor(BiConsumer<Resource, Integer> handler) { resourceVisitor = handler; } public final void setLeafVisitor(BiConsumer<Resource, Integer> handler) { leafVisitor = handler; } public final void setPropertyVisitor(BiConsumer<Map.Entry<String, Object>, Integer> handler) { propertyVisitor = handler; } public final void setBreadthFirstMode() { mode = TraversalMode.BREADTH; } public final void setDepthFirstMode() { mode = TraversalMode.DEPTH; } public void accept(final Resource res) { currentLevel.clear(); nextLevel.clear(); accept(res, 0); } protected void accept(final Resource res, int level) { if (res != null) { if (propertyVisitor != null) { res.getValueMap().entrySet().stream() .filter(e -> propertyFilter.apply(e.getKey())) .forEach(entry -> propertyVisitor.accept(entry, level)); } if (mode == TraversalMode.DEPTH) { if (traversalFilter.apply(res)) { this.traverseChildren(res.listChildren(), level); if (resourceVisitor != null) { resourceVisitor.accept(res, level); } } else { if (leafVisitor != null) { leafVisitor.accept(res, level); } } } else { if (traversalFilter.apply(res)) { if (resourceVisitor != null) { resourceVisitor.accept(res, level); } this.traverseChildren(res.listChildren(), level); } else { if (leafVisitor != null) { leafVisitor.accept(res, level); } this.traverseChildren(Iterators.empty(), level); } } } } protected void traverseChildren(final Iterator<Resource> children, int level) { if (mode == TraversalMode.DEPTH) { while (children.hasNext()) { final Resource child = children.next(); accept(child, level+1); } } else { children.forEachRemaining(nextLevel::add); if (currentLevel.isEmpty()) { currentLevel.addAll(nextLevel); nextLevel.clear(); level++; } Resource res = currentLevel.poll(); if (res != null) { accept(res, level); } } } }