This is an automated email from the ASF dual-hosted git repository.
daim pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/trunk by this push:
new 161cb0c76a OAK-11832 : replaced Guava's TreeTraversal with OAK
commons (#2421)
161cb0c76a is described below
commit 161cb0c76a5da821b024184ac45ec9242bb2c409
Author: Rishabh Kumar <[email protected]>
AuthorDate: Wed Aug 13 13:23:44 2025 +0530
OAK-11832 : replaced Guava's TreeTraversal with OAK commons (#2421)
* OAK-11832 : replaced Guava's TreeTraversal with OAK commons
* OAK-11832 : replaced Guava's TreeTraversal with OAK commons
* Update
oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/Traverser.java
Co-authored-by: Julian Reschke <[email protected]>
* Update
oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/Traverser.java
Co-authored-by: Julian Reschke <[email protected]>
* OAK-11832 : added random data generator test to verify guava & oak
travsersal codes.
* Update
oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/Traverser.java
Co-authored-by: Julian Reschke <[email protected]>
---------
Co-authored-by: Julian Reschke <[email protected]>
---
.../apache/jackrabbit/oak/commons/Traverser.java | 173 +++++++++
.../oak/commons/collections/IterableUtils.java | 2 -
.../jackrabbit/oak/commons/package-info.java | 2 +-
.../jackrabbit/oak/commons/TraverserTest.java | 423 +++++++++++++++++++++
.../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, 638 insertions(+), 62 deletions(-)
diff --git
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/Traverser.java
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/Traverser.java
new file mode 100644
index 0000000000..7ee6fc5cc2
--- /dev/null
+++ b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/Traverser.java
@@ -0,0 +1,173 @@
+/*
+ * 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.apache.commons.collections4.iterators.UnmodifiableIterator;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+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 Traverser {
+
+ private Traverser() {
+ // 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<? extends 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 UnmodifiableIterator.unmodifiableIterator(new
PreOrderIterator<>(root, childExtractor));
+ }
+ });
+ }
+
+ private static final class PreOrderIterator<T> implements Iterator<T> {
+
+ private final Deque<Iterator<? extends T>> stack;
+ private final Function<T, Iterable<? extends T>> childExtractor;
+
+ public PreOrderIterator(final T root, final Function<T, Iterable<?
extends T>> childExtractor) {
+ this.childExtractor = childExtractor;
+ this.stack = new ArrayDeque<>();
+ // add first element during initialization
+ stack.addLast(Collections.singletonList(root).iterator());
+ }
+
+ @Override
+ public boolean hasNext() {
+ // Remove any empty iterators from the top of the stack
+ while (!stack.isEmpty() && !stack.peek().hasNext()) {
+ stack.pop();
+ }
+ return !stack.isEmpty();
+ }
+
+ @Override
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException("No more nodes in the tree");
+ }
+
+ // Get next element from the current iterator
+ T current = stack.peek().next();
+
+ // Push the iterator for children onto the stack
+ // Children added later will be processed first in pre-order
traversal
+ Iterator<? extends T> childIter =
childExtractor.apply(current).iterator();
+ if (childIter.hasNext()) {
+ stack.push(childIter);
+ }
+ 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 sibling 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<? extends 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 UnmodifiableIterator.unmodifiableIterator(new
BreadthFirstIterator<>(root, childExtractor));
+ }
+ });
+ }
+
+ private static final class BreadthFirstIterator<T> implements Iterator<T> {
+
+ private final Deque<T> queue;
+ private final Function<T, Iterable<? extends T>> childExtractor;
+
+ public BreadthFirstIterator(final T root, final Function<T, Iterable<?
extends T>> childExtractor) {
+ this.queue = new ArrayDeque<>();
+ this.childExtractor = childExtractor;
+ this.queue.add(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/TraverserTest.java
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/TraverserTest.java
new file mode 100644
index 0000000000..056e1902be
--- /dev/null
+++
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/TraverserTest.java
@@ -0,0 +1,423 @@
+/*
+ * 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 com.google.common.collect.TreeTraverser;
+import org.apache.commons.collections4.FluentIterable;
+import org.jetbrains.annotations.NotNull;
+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 Traverser}
+ */
+public class TraverserTest {
+
+ @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 = Traverser.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 = Traverser.preOrderTraversal(null,
Node::getChildren);
+ Assert.assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testPreOrderTraversalWithSingleNode() {
+ Node root = new Node(1);
+ List<Integer> result = Traverser.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 = Traverser.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, () ->
Traverser.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 = Traverser.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 = Traverser.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));
+
+ Traverser.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 = Traverser.breadthFirstTraversal(root,
Node::getChildren)
+ .transform(Node::getValue)
+ .toList();
+
+ Assert.assertEquals(Arrays.asList(1, 2, 3, 4, 5, 6, 7), result);
+ }
+
+ @Test
+ public void testPreOrderTraversalWithTree() {
+ // Create a tree structure
+ // 4
+ // / \
+ // 0,2 6
+ // / \
+ // 1,3,5 7,8,9
+ Node root = new Node(4,
+ new Node(0),
+ new Node(2,
+ new Node(1),
+ new Node(3),
+ new Node(5)),
+ new Node(6,
+ new Node(7),
+ new Node(8),
+ new Node(9)));
+
+ List<Integer> result = Traverser.preOrderTraversal(root,
Node::getChildren)
+ .transform(Node::getValue)
+ .toList();
+
+ // In post-order: left subtree, right subtree, root
+ Assert.assertEquals(Arrays.asList(4, 0, 2, 1, 3, 5, 6, 7, 8, 9),
result);
+ }
+
+ // TODO remove this test when we remove guava dependency
+ @Test
+ public void testPreOrderTraversalWithRandomTree() {
+
+ final Node root = getRoot(10000);
+
+ List<Integer> result = Traverser.preOrderTraversal(root,
Node::getChildren)
+ .transform(Node::getValue)
+ .toList();
+
+ // In post-order: left subtree, right subtree, root
+ Assert.assertEquals(result,
traverser.preOrderTraversal(root).transform(Node::getValue).toList());
+ }
+
+ @Test
+ public void testBreadthFirstTraversalWithNullRoot() {
+ FluentIterable<Node> result = Traverser.breadthFirstTraversal(null,
Node::getChildren);
+ Assert.assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testBreadthFirstTraversalWithSingleNode() {
+ Node root = new Node(1);
+ List<Integer> result = Traverser.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 = Traverser.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));
+
+ Traverser.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, () ->
Traverser.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 = Traverser.breadthFirstTraversal(n1,
Node::getChildren)
+ .transform(Node::getValue)
+ .toList();
+
+ Assert.assertEquals(Arrays.asList(1, 2, 3, 4, 5), result);
+ }
+
+ @Test
+ public void testBreadthFirstOrderTraversalWithTree() {
+ // Create a tree structure
+ // 4
+ // / \
+ // 0,2 6
+ // / \
+ // 1,3,5 7,8,9
+ Node root = new Node(4,
+ new Node(0),
+ new Node(2,
+ new Node(1),
+ new Node(3),
+ new Node(5)),
+ new Node(6,
+ new Node(7),
+ new Node(8),
+ new Node(9)));
+
+ List<Integer> result = Traverser.breadthFirstTraversal(root,
Node::getChildren)
+ .transform(Node::getValue)
+ .toList();
+
+ // In post-order: left subtree, right subtree, root
+ Assert.assertEquals(Arrays.asList(4, 0, 2, 6, 1, 3, 5, 7, 8, 9),
result);
+ }
+
+ // TODO remove this test when we remove guava dependency
+ @Test
+ public void testBreadthFirstOrderTraversalWithRandomTree() {
+
+ final Node root = getRoot(10000);
+
+ List<Integer> result = Traverser.breadthFirstTraversal(root,
Node::getChildren)
+ .transform(Node::getValue)
+ .toList();
+
+ // In post-order: left subtree, right subtree, root
+ Assert.assertEquals(result,
traverser.breadthFirstTraversal(root).transform(Node::getValue).toList());
+ }
+
+ // 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);
+ }
+
+ }
+ private @NotNull Node getRoot(final int count) {
+ final Node root = new Node(4);
+
+ List<Node> parents = new ArrayList<>();
+ parents.add(root); // Start with root as the only parent
+
+ java.util.Random random = new java.util.Random();
+ int nodesCreated = 1; // Start at 1 to account for the root
+
+ while (nodesCreated < count && !parents.isEmpty()) {
+ List<Node> nextParents = new ArrayList<>();
+
+ // For each current parent
+ for (Node parent : parents) {
+ // Randomly determine how many children to add (0-5)
+ int numChildren = random.nextInt(6);
+
+ // Make sure we don't exceed the total count
+ numChildren = Math.min(numChildren, count - nodesCreated);
+
+ // Add the random number of children
+ for (int i = 0; i < numChildren; i++) {
+ Node child = new Node(nodesCreated + 4); // Unique value
+ parent.addChild(child);
+ nodesCreated++;
+
+ // Each child has a chance to become a parent in the next
round
+ if (random.nextBoolean()) {
+ nextParents.add(child);
+ }
+ }
+ }
+ // Update parents for the next round
+ parents = nextParents;
+ }
+ return root;
+ }
+
+ final TreeTraverser<Node> traverser = new TreeTraverser<>() {
+
+ @Override
+ public Iterable<Node> children(Node root) {
+ return root.getChildren();
+ }
+ };
+}
\ 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..0986a6f0d7 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.Traverser;
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<? extends 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 : Traverser.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..f1dd71f446 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.Traverser;
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<? extends LuceneDoc>> docGetter
= root -> {
+ if (root.depth >= maxLevel) {
+ return Collections.emptyList();
}
+ return root.getChildren();
};
- for (LuceneDoc node : traverser.breadthFirstTraversal(doc)) {
+ for (LuceneDoc node : Traverser.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..37df70899b 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.Traverser;
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<? extends NodeState>> children = root ->
IterableUtils.transform(root.getChildNodeEntries(),
ChildNodeEntry::getNodeState);
+
AtomicInteger matches = new AtomicInteger();
- int totalCount = t.preOrderTraversal(bucket)
- .transform((st) -> {
+ int totalCount = Traverser.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..ce33fe0a3c 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.Traverser;
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<? extends NodeState>> children =
root -> IterableUtils.transform(root.getChildNodeEntries(),
ChildNodeEntry::getNodeState);
+
+ return Traverser.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..ba1add35f3 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.Traverser;
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 Traverser
+
.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<? extends 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..7ef95028b5 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.Traverser;
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<? extends
DocumentNodeState>> children = root ->
IterableUtils.transform(root::getBundledChildren, ce -> (DocumentNodeState)
ce.getNodeState());
+
+ return Traverser.preOrderTraversal(this, children)
+ .filter(dns -> !dns.getPath().equals(this.getPath()) );
//Exclude this
}
/**