This is an automated email from the ASF dual-hosted git repository. daim pushed a commit to branch OAK-11832 in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 05ec24dc29de654951bbbf693563c35a3a615b25 Author: rishabhdaim <[email protected]> AuthorDate: Fri Aug 1 16:13:42 2025 +0530 OAK-11832 : replaced Guava's TreeTraversal with OAK commons --- .../jackrabbit/oak/commons/TreeTraverser.java | 158 +++++++++++ .../oak/commons/collections/IterableUtils.java | 2 - .../jackrabbit/oak/commons/package-info.java | 2 +- .../jackrabbit/oak/commons/TreeTraverserTest.java | 294 +++++++++++++++++++++ .../index/property/jmx/PropertyIndexStats.java | 21 +- .../plugins/index/lucene/LuceneIndexMBeanImpl.java | 19 +- .../lucene/property/HybridPropertyIndexInfo.java | 16 +- .../index/lucene/property/RecursiveDeleteTest.java | 14 +- .../tika/NodeStoreBinaryResourceProvider.java | 16 +- .../oak/plugins/document/DocumentNodeState.java | 14 +- 10 files changed, 494 insertions(+), 62 deletions(-) diff --git a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/TreeTraverser.java b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/TreeTraverser.java new file mode 100644 index 0000000000..c0e93e8770 --- /dev/null +++ b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/TreeTraverser.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.jackrabbit.oak.commons; + +import org.apache.commons.collections4.FluentIterable; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Function; + +public class TreeTraverser { + + private TreeTraverser() { + // no instances for you + } + + /** + * Returns an iterator that traverses a tree structure in pre-order. Null nodes are strictly forbidden. + * <p> + * In pre-order traversal, the current node is visited first, followed by its children + * from left to right. This method creates an iterator that produces tree nodes in this order. + * + * @param <T> the type of value in the tree nodes + * @param root the root node of the tree, may be null + * @param childExtractor function to extract children from a node, must not be null + * @return an iterator that traverses the tree in pre-order + * @throws NullPointerException if childExtractor or any child is null + */ + @NotNull + public static <T> FluentIterable<T> preOrderTraversal(final T root, final @NotNull Function<T, Iterable<T>> childExtractor) { + + Objects.requireNonNull(childExtractor, "Children extractor function must not be null"); + + if (root == null) { + return FluentIterable.empty(); + } + + return FluentIterable.of(new Iterable<>() { + @Override + public @NotNull Iterator<T> iterator() { + return new Iterator<>() { + private final Deque<T> stack = new ArrayDeque<>(); + + { + // add first element during initialization + stack.push(root); + } + + @Override + public boolean hasNext() { + return !stack.isEmpty(); + } + + @Override + public T next() { + if (!hasNext()) { + throw new NoSuchElementException("No more nodes in the tree"); + } + + final T current = stack.pop(); + + // Push children in reverse order so they're popped in correct order + List<T> children = new ArrayList<>(); + // NPE if the current is null + childExtractor.apply(current).forEach(children::add); + + for (int i = children.size() - 1; i >= 0; i--) { + // NPE if the child is null + stack.push(children.get(i)); + } + return current; + } + }; + } + }); + } + + /** + * Returns an iterator that traverses a tree structure in breadth-first order. + * Null nodes are strictly forbidden. + * <p> + * In breadth-first traversal, all nodes at a given level are visited before any nodes + * at the next level. This creates a level-by-level traversal pattern, starting from the root + * and moving downward through the tree. + * + * @param <T> the type of value in the tree nodes + * @param root the root node of the tree, may be null + * @param childExtractor function to extract children from a node, must not be null + * @return a fluent iterable that traverses the tree in breadth-first order + * @throws NullPointerException if childExtractor or any child is null + */ + @NotNull + public static <T> FluentIterable<T> breadthFirstTraversal(final T root, final @NotNull Function<T, Iterable<T>> childExtractor) { + Objects.requireNonNull(childExtractor, "Children extractor function must not be null"); + + if (root == null) { + return FluentIterable.empty(); + } + + return FluentIterable.of(new Iterable<>() { + @Override + public @NotNull Iterator<T> iterator() { + return new Iterator<>() { + private final Deque<T> queue = new ArrayDeque<>(); + + { + // add first element during initialization + queue.addLast(root); + } + + @Override + public boolean hasNext() { + return !queue.isEmpty(); + } + + @Override + public T next() { + if (!hasNext()) { + throw new NoSuchElementException("No more nodes in the tree"); + } + + final T current = queue.removeFirst(); + + // Add all children to the queue (in order) + for (T child : childExtractor.apply(current)) { + // would throw NPE if the child is null + queue.addLast(child); + } + return current; + } + }; + } + }); + } +} diff --git a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IterableUtils.java b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IterableUtils.java index 4f93afc75f..f7e490d68c 100644 --- a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IterableUtils.java +++ b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IterableUtils.java @@ -23,12 +23,10 @@ import org.apache.jackrabbit.oak.commons.conditions.Validate; import org.jetbrains.annotations.NotNull; import java.lang.reflect.Array; -import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.List; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; diff --git a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java index 718a93ef89..628d8b92bb 100644 --- a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java +++ b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("2.4.0") +@Version("2.5.0") package org.apache.jackrabbit.oak.commons; import org.osgi.annotation.versioning.Version; diff --git a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/TreeTraverserTest.java b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/TreeTraverserTest.java new file mode 100644 index 0000000000..2978a97799 --- /dev/null +++ b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/TreeTraverserTest.java @@ -0,0 +1,294 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.jackrabbit.oak.commons; + +import org.apache.commons.collections4.FluentIterable; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Unit cases for {@link TreeTraverser} + */ +public class TreeTraverserTest { + + @Test + public void testPreOrderTraversalWithNormalTree() { + // Create a simple tree structure: + // 1 + // / \ + // 2 3 + // / \ / \ + // 4 5 6 7 + Node root = new Node(1, + new Node(2, + new Node(4), + new Node(5)), + new Node(3, + new Node(6), + new Node(7))); + + List<Integer> result = TreeTraverser.preOrderTraversal(root, Node::getChildren) + .transform(Node::getValue) + .toList(); + + // In pre-order: visit root, then left subtree, then right subtree + Assert.assertEquals(Arrays.asList(1, 2, 4, 5, 3, 6, 7), result); + } + + @Test + public void testPreOrderTraversalWithNullRoot() { + FluentIterable<Node> result = TreeTraverser.preOrderTraversal(null, Node::getChildren); + Assert.assertTrue(result.isEmpty()); + } + + @Test + public void testPreOrderTraversalWithSingleNode() { + Node root = new Node(1); + List<Integer> result = TreeTraverser.preOrderTraversal(root, Node::getChildren) + .transform(Node::getValue) + .toList(); + + Assert.assertEquals(Collections.singletonList(1), result); + } + + @Test + public void testPreOrderTraversalWithAsymmetricTree() { + // Create an asymmetric tree: + // 1 + // / \ + // 2 3 + // / \ + // 4 7 + // \ + // 5 + Node root = new Node(1, + new Node(2, + new Node(4, + new Node(5))), + new Node(3, + new Node(7))); + + List<Integer> result = TreeTraverser.preOrderTraversal(root, Node::getChildren) + .transform(Node::getValue) + .toList(); + + // In pre-order: visit nodes as they're encountered depth-first + Assert.assertEquals(Arrays.asList(1, 2, 4, 5, 3, 7), result); + } + + @Test + public void testPreOrderTraversalWithNullChildExtractor() { + Node root = new Node(1); + Assert.assertThrows(NullPointerException.class, () -> TreeTraverser.preOrderTraversal(root, null)); + } + + @Test + public void testPreOrderTraversalWithDeepTree() { + // Create a deep tree with many levels (linked-list-like) + Node n1 = new Node(1); + Node n2 = new Node(2); + Node n3 = new Node(3); + Node n4 = new Node(4); + Node n5 = new Node(5); + + n1.addChild(n2); + n2.addChild(n3); + n3.addChild(n4); + n4.addChild(n5); + + List<Integer> result = TreeTraverser.preOrderTraversal(n1, Node::getChildren) + .transform(Node::getValue) + .toList(); + + // Should visit in depth-first order + Assert.assertEquals(Arrays.asList(1, 2, 3, 4, 5), result); + } + + @Test + public void testPreOrderTraversalWithBinarySearchTree() { + // Create a binary search tree structure + // 4 + // / \ + // 2 6 + // / \ / \ + // 1 3 5 7 + Node root = new Node(4, + new Node(2, + new Node(1), + new Node(3)), + new Node(6, + new Node(5), + new Node(7))); + + List<Integer> result = TreeTraverser.preOrderTraversal(root, Node::getChildren) + .transform(Node::getValue) + .toList(); + + // In pre-order: root, left subtree, right subtree + Assert.assertEquals(Arrays.asList(4, 2, 1, 3, 6, 5, 7), result); + } + + @Test(expected = NullPointerException.class) + public void testPreOrderTraversalWithNullChildren() { + // A tree with some null children + Node root = new Node(1, + null, + new Node(3)); + + TreeTraverser.preOrderTraversal(root, Node::getChildren).transform(Node::getValue).forEach(System.out::println); + + Assert.fail("Shouldn't reach here"); + } + + @Test + public void testBreadthFirstTraversalWithNormalTree() { + // Create a simple tree structure: + // 1 + // / \ + // 2 3 + // / \ / \ + // 4 5 6 7 + Node root = new Node(1, + new Node(2, + new Node(4), + new Node(5)), + new Node(3, + new Node(6), + new Node(7))); + + List<Integer> result = TreeTraverser.breadthFirstTraversal(root, Node::getChildren) + .transform(Node::getValue) + .toList(); + + Assert.assertEquals(Arrays.asList(1, 2, 3, 4, 5, 6, 7), result); + } + + @Test + public void testBreadthFirstTraversalWithNullRoot() { + FluentIterable<Node> result = TreeTraverser.breadthFirstTraversal(null, Node::getChildren); + Assert.assertTrue(result.isEmpty()); + } + + @Test + public void testBreadthFirstTraversalWithSingleNode() { + Node root = new Node(1); + List<Integer> result = TreeTraverser.breadthFirstTraversal(root, Node::getChildren) + .transform(Node::getValue) + .toList(); + + Assert.assertEquals(Collections.singletonList(1), result); + } + + @Test + public void testBreadthFirstTraversalWithAsymmetricTree() { + // Create an asymmetric tree: + // 1 + // / \ + // 2 3 + // / \ + // 4 7 + // \ + // 5 + Node root = new Node(1, + new Node(2, + new Node(4, + new Node(5))), + new Node(3, + new Node(7))); + + List<Integer> result = TreeTraverser.breadthFirstTraversal(root, Node::getChildren) + .transform(Node::getValue) + .toList(); + + Assert.assertEquals(Arrays.asList(1, 2, 3, 4, 7, 5), result); + } + + @Test(expected = NullPointerException.class) + public void testBreadthFirstTraversalWithNullChildren() { + // A tree with some null children + Node root = new Node(1, + null, + new Node(3)); + + TreeTraverser.breadthFirstTraversal(root, Node::getChildren).transform(Node::getValue).forEach(System.out::println); + + Assert.fail("Shouldn't reach here"); + } + + @Test + public void testBreadthFirstTraversalWithNullChildExtractor() { + Node root = new Node(1); + Assert.assertThrows(NullPointerException.class, () -> TreeTraverser.breadthFirstTraversal(root, null)); + } + + @Test + public void testBreadthFirstTraversalWithDeepTree() { + // Create a deep tree with many levels + Node n1 = new Node(1); + Node n2 = new Node(2); + Node n3 = new Node(3); + Node n4 = new Node(4); + Node n5 = new Node(5); + + n1.addChild(n2); + n2.addChild(n3); + n3.addChild(n4); + n4.addChild(n5); + + List<Integer> result = TreeTraverser.breadthFirstTraversal(n1, Node::getChildren) + .transform(Node::getValue) + .toList(); + + Assert.assertEquals(Arrays.asList(1, 2, 3, 4, 5), result); + } + + // Helper class for testing tree traversal + private static class Node { + private final int value; + private final List<Node> children = new ArrayList<>(); + + public Node(int value, Node... children) { + this.value = value; + this.children.addAll(Arrays.asList(children)); + } + + public int getValue() { + return value; + } + + public Iterable<Node> getChildren() { + return children; + } + + public void addChild(Node child) { + children.add(child); + } + + @Override + public String toString() { + return Integer.toString(value); + } + } +} \ No newline at end of file diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/jmx/PropertyIndexStats.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/jmx/PropertyIndexStats.java index 279002a4e2..c938052f55 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/jmx/PropertyIndexStats.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/jmx/PropertyIndexStats.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.Function; import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; @@ -36,11 +37,11 @@ import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; -import org.apache.jackrabbit.guava.common.collect.TreeTraverser; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.api.Type; import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.commons.TreeTraverser; import org.apache.jackrabbit.oak.commons.collections.IterableUtils; import org.apache.jackrabbit.oak.commons.jmx.AnnotatedStandardMBean; import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard; @@ -50,7 +51,6 @@ import org.apache.jackrabbit.oak.spi.state.NodeState; import org.apache.jackrabbit.oak.spi.state.NodeStateUtils; import org.apache.jackrabbit.oak.spi.state.NodeStore; import org.apache.jackrabbit.oak.spi.whiteboard.Registration; -import org.jetbrains.annotations.NotNull; import org.osgi.framework.BundleContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -168,17 +168,16 @@ public class PropertyIndexStats extends AnnotatedStandardMBean implements Proper topLevel: for (ChildNodeEntry cne : values) { Tree t = TreeFactory.createReadOnlyTree(cne.getNodeState()); - TreeTraverser<Tree> traverser = new TreeTraverser<Tree>() { - @Override - public Iterable<Tree> children(@NotNull Tree root) { - //Break at maxLevel - if (PathUtils.getDepth(root.getPath()) >= maxDepth) { - return Collections.emptyList(); - } - return root.getChildren(); + + final Function<Tree, Iterable<Tree>> treeGetter = root -> { + //Break at maxLevel + if (PathUtils.getDepth(root.getPath()) >= maxDepth) { + return Collections.emptyList(); } + return root.getChildren(); }; - for (Tree node : traverser.breadthFirstTraversal(t)) { + + for (Tree node : TreeTraverser.breadthFirstTraversal(t, treeGetter)) { PropertyState matchState = node.getProperty("match"); boolean match = matchState == null ? false : matchState.getValue(Type.BOOLEAN); int depth = PathUtils.getDepth(node.getPath()); diff --git a/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBeanImpl.java b/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBeanImpl.java index bbc50c3c12..5af577f7e4 100644 --- a/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBeanImpl.java +++ b/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBeanImpl.java @@ -48,6 +48,7 @@ import javax.management.openmbean.TabularType; import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.api.jmx.Name; import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.commons.TreeTraverser; import org.apache.jackrabbit.oak.commons.collections.IterableUtils; import org.apache.jackrabbit.oak.commons.jmx.AnnotatedStandardMBean; import org.apache.jackrabbit.oak.commons.json.JsopBuilder; @@ -90,13 +91,10 @@ import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.IOContext; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.NumericUtils; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.jackrabbit.guava.common.collect.TreeTraverser; - public class LuceneIndexMBeanImpl extends AnnotatedStandardMBean implements LuceneIndexMBean { private static final boolean LOAD_INDEX_FOR_STATS = Boolean.parseBoolean(System.getProperty("oak.lucene.LoadIndexForStats", "false")); @@ -558,18 +556,15 @@ public class LuceneIndexMBeanImpl extends AnnotatedStandardMBean implements Luce int maxPathLimitBreachedAtLevel = -1; topLevel: for (LuceneDoc doc : docs){ - TreeTraverser<LuceneDoc> traverser = new TreeTraverser<LuceneDoc>() { - @Override - public Iterable<LuceneDoc> children(@NotNull LuceneDoc root) { - //Break at maxLevel - if (root.depth >= maxLevel) { - return Collections.emptyList(); - } - return root.getChildren(); + + final Function<LuceneDoc, Iterable<LuceneDoc>> docGetter = root -> { + if (root.depth >= maxLevel) { + return Collections.emptyList(); } + return root.getChildren(); }; - for (LuceneDoc node : traverser.breadthFirstTraversal(doc)) { + for (LuceneDoc node : TreeTraverser.breadthFirstTraversal(doc, docGetter)) { if (paths.size() < maxPathCount) { paths.add(node.path); } else { diff --git a/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexInfo.java b/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexInfo.java index 5bb0d507cd..b3de7ec0c2 100644 --- a/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexInfo.java +++ b/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexInfo.java @@ -21,8 +21,9 @@ package org.apache.jackrabbit.oak.plugins.index.lucene.property; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; -import org.apache.jackrabbit.guava.common.collect.TreeTraverser; +import org.apache.jackrabbit.oak.commons.TreeTraverser; import org.apache.jackrabbit.oak.commons.collections.IterableUtils; import org.apache.jackrabbit.oak.commons.json.JsopBuilder; import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry; @@ -88,15 +89,12 @@ public class HybridPropertyIndexInfo { } private void collectCounts(NodeState bucket) { - TreeTraverser<NodeState> t = new TreeTraverser<NodeState>() { - @Override - public Iterable<NodeState> children(NodeState root) { - return IterableUtils.transform(root.getChildNodeEntries(), ChildNodeEntry::getNodeState); - } - }; + + Function<NodeState, Iterable<NodeState>> children = root -> IterableUtils.transform(root.getChildNodeEntries(), ChildNodeEntry::getNodeState); + AtomicInteger matches = new AtomicInteger(); - int totalCount = t.preOrderTraversal(bucket) - .transform((st) -> { + int totalCount = TreeTraverser.preOrderTraversal(bucket, children) + .transform(st -> { if (st.getBoolean("match")) { matches.incrementAndGet(); } diff --git a/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/RecursiveDeleteTest.java b/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/RecursiveDeleteTest.java index 3bf2ab378a..ade524afff 100644 --- a/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/RecursiveDeleteTest.java +++ b/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/RecursiveDeleteTest.java @@ -24,9 +24,10 @@ import java.util.Collection; import java.util.List; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; -import org.apache.jackrabbit.guava.common.collect.TreeTraverser; import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.commons.TreeTraverser; import org.apache.jackrabbit.oak.commons.collections.IterableUtils; import org.apache.jackrabbit.oak.fixture.DocumentMemoryFixture; import org.apache.jackrabbit.oak.fixture.MemoryFixture; @@ -149,13 +150,10 @@ public class RecursiveDeleteTest { } private int getSubtreeCount(NodeState state){ - TreeTraverser<NodeState> t = new TreeTraverser<NodeState>() { - @Override - public Iterable<NodeState> children(NodeState root) { - return IterableUtils.transform(root.getChildNodeEntries(), ChildNodeEntry::getNodeState); - } - }; - return t.preOrderTraversal(state).size(); + + final Function<NodeState, Iterable<NodeState>> children = root -> IterableUtils.transform(root.getChildNodeEntries(), ChildNodeEntry::getNodeState); + + return TreeTraverser.preOrderTraversal(state, children).size(); } } diff --git a/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/tika/NodeStoreBinaryResourceProvider.java b/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/tika/NodeStoreBinaryResourceProvider.java index 30144ca739..b7b280ada0 100644 --- a/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/tika/NodeStoreBinaryResourceProvider.java +++ b/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/tika/NodeStoreBinaryResourceProvider.java @@ -19,12 +19,12 @@ package org.apache.jackrabbit.oak.plugins.tika; import org.apache.commons.collections4.FluentIterable; -import org.apache.jackrabbit.guava.common.collect.TreeTraverser; import org.apache.jackrabbit.JcrConstants; import org.apache.jackrabbit.oak.api.Blob; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.api.Type; +import org.apache.jackrabbit.oak.commons.TreeTraverser; import org.apache.jackrabbit.oak.spi.blob.BlobStore; import org.apache.jackrabbit.oak.spi.state.NodeStore; import org.jetbrains.annotations.Nullable; @@ -49,11 +49,10 @@ class NodeStoreBinaryResourceProvider implements BinaryResourceProvider { public FluentIterable<BinaryResource> getBinaries(String path) { // had to convert Guava's FluentIterable to Apache Commons Collections FluentIterable - // TODO once we remove preOrderTraversal() of Guava, we can use Apache FluentIterable directly - return FluentIterable.of(new OakTreeTraverser() - .preOrderTraversal(createReadOnlyTree(getNode(nodeStore.getRoot(), path))) + return TreeTraverser + .preOrderTraversal(createReadOnlyTree(getNode(nodeStore.getRoot(), path)), treeTraverser) .transform(new TreeToBinarySource()::apply) - .filter(Objects::nonNull)); + .filter(Objects::nonNull); } private class TreeToBinarySource implements Function<Tree, BinaryResource> { @@ -87,12 +86,7 @@ class NodeStoreBinaryResourceProvider implements BinaryResourceProvider { } } - private static class OakTreeTraverser extends TreeTraverser<Tree> { - @Override - public Iterable<Tree> children(Tree root) { - return root.getChildren(); - } - } + final Function<Tree, Iterable<Tree>> treeTraverser = Tree::getChildren; @Nullable private static String getString(Tree tree, String name) { diff --git a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java index 2a49eb09c5..15a3f57d16 100644 --- a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java +++ b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java @@ -23,10 +23,11 @@ import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; +import java.util.function.Function; -import org.apache.jackrabbit.guava.common.collect.TreeTraverser; import org.apache.jackrabbit.oak.api.Type; import org.apache.jackrabbit.oak.cache.CacheValue; +import org.apache.jackrabbit.oak.commons.TreeTraverser; import org.apache.jackrabbit.oak.commons.collections.IterableUtils; import org.apache.jackrabbit.oak.commons.collections.IteratorUtils; import org.apache.jackrabbit.oak.commons.conditions.Validate; @@ -496,13 +497,10 @@ public class DocumentNodeState extends AbstractDocumentNodeState implements Cach } public Iterable<DocumentNodeState> getAllBundledNodesStates() { - return new TreeTraverser<DocumentNodeState>(){ - @Override - public Iterable<DocumentNodeState> children(DocumentNodeState root) { - return IterableUtils.transform(() -> root.getBundledChildren(), ce -> (DocumentNodeState)ce.getNodeState()); - } - }.preOrderTraversal(this) - .filter(dns -> !dns.getPath().equals(this.getPath()) ); //Exclude this + final Function<DocumentNodeState, Iterable<DocumentNodeState>> children = root -> IterableUtils.transform(root::getBundledChildren, ce -> (DocumentNodeState) ce.getNodeState()); + + return TreeTraverser.preOrderTraversal(this, children) + .filter(dns -> !dns.getPath().equals(this.getPath()) ); //Exclude this } /**
