This is an automated email from the ASF dual-hosted git repository.

daim pushed a commit to branch OAK-11458
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git

commit 8753df25e0350b481ab43db51669533865996d9b
Author: Rishabh Kumar <[email protected]>
AuthorDate: Thu Feb 6 13:17:17 2025 +0530

    OAK-11458 : added utils class for repalcing Guava's Iterables
---
 oak-commons/pom.xml                                |   9 +-
 .../oak/commons/collections/IterableUtils.java     | 145 ++++++++++++++++++
 .../oak/commons/collections/package-info.java      |   2 +-
 .../oak/commons/collections/IterableUtilsTest.java | 169 +++++++++++++++++++++
 4 files changed, 319 insertions(+), 6 deletions(-)

diff --git a/oak-commons/pom.xml b/oak-commons/pom.xml
index d89a934f6d..385104b03c 100644
--- a/oak-commons/pom.xml
+++ b/oak-commons/pom.xml
@@ -96,6 +96,10 @@
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-collections4</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.jackrabbit</groupId>
       <artifactId>jackrabbit-jcr-commons</artifactId>
@@ -128,11 +132,6 @@
       <artifactId>commons-lang3</artifactId>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-collections4</artifactId>
-      <scope>test</scope>
-    </dependency>
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
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
new file mode 100644
index 0000000000..7688db8950
--- /dev/null
+++ 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/IterableUtils.java
@@ -0,0 +1,145 @@
+/*
+ * 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.collections;
+
+import org.apache.commons.collections4.iterators.LazyIteratorChain;
+
+import java.util.Iterator;
+import java.util.Objects;
+
+/**
+ * Utility methods for {@link Iterable} conversions.
+ */
+public class IterableUtils {
+
+    private IterableUtils() {
+        // no instances for you
+    }
+
+    /**
+     * Combines two iterables into a single iterable.
+     * <p>
+     * The returned iterable has an iterator that traverses the elements in 
{@code a},
+     * followed by the elements in {@code b}. The source iterators are not 
polled until necessary.
+     * <p>
+     * The returned iterable's iterator supports {@code remove()} when the 
corresponding
+     * input iterator supports it.
+     *
+     * @param <E> the element type
+     * @param a  the first iterable, may not be null
+     * @param b  the second iterable, may not be null
+     * @return a new iterable, combining the provided iterables
+     * @throws NullPointerException if either of the provided iterables is null
+     */
+    public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> 
a,
+                                                  final Iterable<? extends E> 
b) {
+        return chainedIterable(new Iterable[] {a, b});
+    }
+
+    /**
+     * Combines three iterables into a single iterable.
+     * <p>
+     * The returned iterable has an iterator that traverses the elements in 
{@code a},
+     * followed by the elements in {@code b} and {@code c}. The source
+     * iterators are not polled until necessary.
+     * <p>
+     * The returned iterable's iterator supports {@code remove()} when the 
corresponding
+     * input iterator supports it.
+     *
+     * @param <E> the element type
+     * @param a  the first iterable, may not be null
+     * @param b  the second iterable, may not be null
+     * @param c  the third iterable, may not be null
+     * @return a new iterable, combining the provided iterables
+     * @throws NullPointerException if either of the provided iterables is null
+     */
+    public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> 
a,
+                                                  final Iterable<? extends E> 
b,
+                                                  final Iterable<? extends E> 
c) {
+        return chainedIterable(new Iterable[] {a, b, c});
+    }
+
+    /**
+     * Combines four iterables into a single iterable.
+     * <p>
+     * The returned iterable has an iterator that traverses the elements in 
{@code a},
+     * followed by the elements in {@code b}, {@code c} and {@code d}. The 
source
+     * iterators are not polled until necessary.
+     * <p>
+     * The returned iterable's iterator supports {@code remove()} when the 
corresponding
+     * input iterator supports it.
+     *
+     * @param <E> the element type
+     * @param a  the first iterable, may not be null
+     * @param b  the second iterable, may not be null
+     * @param c  the third iterable, may not be null
+     * @param d  the fourth iterable, may not be null
+     * @return a new iterable, combining the provided iterables
+     * @throws NullPointerException if either of the provided iterables is null
+     */
+    public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> 
a,
+                                                  final Iterable<? extends E> 
b,
+                                                  final Iterable<? extends E> 
c,
+                                                  final Iterable<? extends E> 
d) {
+        return chainedIterable(new Iterable[] {a, b, c, d});
+    }
+
+    /**
+     * Combines the provided iterables into a single iterable.
+     * <p>
+     * The returned iterable has an iterator that traverses the elements in 
the order
+     * of the arguments, i.e. iterables[0], iterables[1], .... The source 
iterators
+     * are not polled until necessary.
+     * <p>
+     * The returned iterable's iterator supports {@code remove()} when the 
corresponding
+     * input iterator supports it.
+     *
+     * @param <E> the element type
+     * @param iterables  the iterables to combine, may not be null
+     * @return a new iterable, combining the provided iterables
+     * @throws NullPointerException if either of the provided iterables is null
+     */
+    @SafeVarargs
+    public static <E> Iterable<E> chainedIterable(final Iterable<? extends 
E>... iterables) {
+        Objects.requireNonNull(iterables);
+        return 
org.apache.commons.collections4.IterableUtils.chainedIterable(iterables);
+    }
+
+    /**
+     * Creates an {@code Iterable} that chains multiple {@code Iterable} 
instances into a single {@code Iterable}.
+     * <p>
+     * The returned {@code Iterable} will iterate over all elements of the 
first {@code Iterable},
+     * then all elements of the second, and so on.
+     *
+     * @param <E> the type of elements returned by the iterator
+     * @param iterables an {@code Iterable} of {@code Iterable} instances to 
be chained
+     * @return an {@code Iterable} that provides a single view of all elements 
in the input {@code Iterable} instances
+     * @throws NullPointerException if the input {@code Iterable} or any of 
its elements are null
+     */
+    public static <E> Iterable<E> chainedIterable(final Iterable<? extends 
Iterable<? extends E>> iterables) {
+        Objects.requireNonNull(iterables);
+        return () -> new LazyIteratorChain<>() {
+            private final Iterator<? extends Iterable<? extends E>> iterator = 
iterables.iterator();
+
+            protected Iterator<? extends E> nextIterator(int count) {
+                return iterator.hasNext() ? iterator.next().iterator() : null;
+            }
+        };
+    }
+}
diff --git 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/package-info.java
 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/package-info.java
index 95dfb8621e..fa16acc93d 100644
--- 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/package-info.java
+++ 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/package-info.java
@@ -21,7 +21,7 @@
  * Utilities for Java collections and streams.
  */
 @Internal(since = "1.0.0")
-@Version("2.0.0")
+@Version("2.1.0")
 package org.apache.jackrabbit.oak.commons.collections;
 import org.apache.jackrabbit.oak.commons.annotations.Internal;
 import org.osgi.annotation.versioning.Version;
diff --git 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IterableUtilsTest.java
 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IterableUtilsTest.java
new file mode 100644
index 0000000000..6a620a6fc6
--- /dev/null
+++ 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/collections/IterableUtilsTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.collections;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Unit tests for the {@link IterableUtils} class.
+ * <p>
+ * This class contains test cases to verify the functionality of the methods
+ * in the {@link IterableUtils} class.
+ */
+public class IterableUtilsTest {
+
+
+    @Test
+    public void testTwoChainedIterable() {
+        List<Integer> list1 = Arrays.asList(1, 2, 3);
+        List<Integer> list2 = Arrays.asList(4, 5);
+
+        Iterable<Integer> chained = IterableUtils.chainedIterable(list1, 
list2);
+
+        Iterator<Integer> iterator = chained.iterator();
+        List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5);
+        for (Integer value : expected) {
+            Assert.assertTrue(iterator.hasNext());
+            Assert.assertEquals(value, iterator.next());
+        }
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testThreeChainedIterable() {
+        List<Integer> list1 = Arrays.asList(1, 2, 3);
+        List<Integer> list2 = Arrays.asList(4, 5);
+        List<Integer> list3 = Arrays.asList(6, 7, 8, 9);
+
+        Iterable<Integer> chained = IterableUtils.chainedIterable(list1, 
list2, list3);
+
+        Iterator<Integer> iterator = chained.iterator();
+        List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
+        for (Integer value : expected) {
+            Assert.assertTrue(iterator.hasNext());
+            Assert.assertEquals(value, iterator.next());
+        }
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testChainedIterable() {
+        List<Integer> list1 = Arrays.asList(1, 2, 3);
+        List<Integer> list2 = Arrays.asList(4, 5);
+        List<Integer> list3 = Arrays.asList(6, 7, 8, 9);
+
+        Iterable<Iterable<Integer>> iterables = Arrays.asList(list1, list2, 
list3);
+        Iterable<Integer> chained = IterableUtils.chainedIterable(iterables);
+
+        Iterator<Integer> iterator = chained.iterator();
+        List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
+        for (Integer value : expected) {
+            Assert.assertTrue(iterator.hasNext());
+            Assert.assertEquals(value, iterator.next());
+        }
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testFourChainedIterable() {
+        List<Integer> list1 = Arrays.asList(1, 2, 3);
+        List<Integer> list2 = Arrays.asList(4, 5);
+        List<Integer> list3 = Arrays.asList(6, 7, 8, 9);
+        List<Integer> list4 = Arrays.asList(10, 11, 12, 13);
+
+        Iterable<Integer> chained = IterableUtils.chainedIterable(list1, 
list2, list3, list4);
+
+        Iterator<Integer> iterator = chained.iterator();
+        List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
11, 12, 13);
+        for (Integer value : expected) {
+            Assert.assertTrue(iterator.hasNext());
+            Assert.assertEquals(value, iterator.next());
+        }
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testChainedIterableVaragrs() {
+        List<Integer> list1 = Arrays.asList(1, 2, 3);
+        List<Integer> list2 = Arrays.asList(4, 5);
+        List<Integer> list3 = Arrays.asList(6, 7, 8, 9);
+        List<Integer> list4 = Arrays.asList(10, 11, 12, 13);
+        List<Integer> list5 = Arrays.asList(14, 15, 16);
+
+        Iterable<Integer> chained = IterableUtils.chainedIterable(list1, 
list2, list3, list4, list5);
+
+        Iterator<Integer> iterator = chained.iterator();
+        List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
11, 12, 13, 14, 15, 16);
+        for (Integer value : expected) {
+            Assert.assertTrue(iterator.hasNext());
+            Assert.assertEquals(value, iterator.next());
+        }
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testChainedIterableEmpty() {
+        Iterable<Iterable<Integer>> iterables = Collections.emptyList();
+        Iterable<Integer> chained = IterableUtils.chainedIterable(iterables);
+
+        Iterator<Integer> iterator = chained.iterator();
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testChainedIterableSingle() {
+        List<Integer> list = Arrays.asList(1, 2, 3);
+        Iterable<Iterable<Integer>> iterables = 
Collections.singletonList(list);
+        Iterable<Integer> chained = IterableUtils.chainedIterable(iterables);
+
+        Iterator<Integer> iterator = chained.iterator();
+        List<Integer> expected = Arrays.asList(1, 2, 3);
+        for (Integer value : expected) {
+            Assert.assertTrue(iterator.hasNext());
+            Assert.assertEquals(value, iterator.next());
+        }
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testChainedIterableNullElement() {
+        List<Integer> list1 = Arrays.asList(1, 2, 3);
+        List<Integer> list2 = null;
+        List<Integer> list3 = Arrays.asList(6, 7, 8, 9);
+
+        Iterable<Iterable<Integer>> iterables = Arrays.asList(list1, list2, 
list3);
+        Iterable<Integer> chained = IterableUtils.chainedIterable(iterables);
+
+        Iterator<Integer> iterator = chained.iterator();
+        List<Integer> expected = Arrays.asList(1, 2, 3);
+        for (Integer value : expected) {
+            Assert.assertTrue(iterator.hasNext());
+            Assert.assertEquals(value, iterator.next());
+        }
+
+        // now next iterator should be null
+        Assert.assertThrows(NullPointerException.class, iterator::hasNext);
+    }
+}

Reply via email to