Skip to content

Commit 8753df2

Browse files
author
Rishabh Kumar
committed
OAK-11458 : added utils class for repalcing Guava's Iterables
1 parent 7d24112 commit 8753df2

File tree

4 files changed

+319
-6
lines changed

4 files changed

+319
-6
lines changed

oak-commons/pom.xml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@
9696
<groupId>commons-io</groupId>
9797
<artifactId>commons-io</artifactId>
9898
</dependency>
99+
<dependency>
100+
<groupId>org.apache.commons</groupId>
101+
<artifactId>commons-collections4</artifactId>
102+
</dependency>
99103
<dependency>
100104
<groupId>org.apache.jackrabbit</groupId>
101105
<artifactId>jackrabbit-jcr-commons</artifactId>
@@ -128,11 +132,6 @@
128132
<artifactId>commons-lang3</artifactId>
129133
<scope>test</scope>
130134
</dependency>
131-
<dependency>
132-
<groupId>org.apache.commons</groupId>
133-
<artifactId>commons-collections4</artifactId>
134-
<scope>test</scope>
135-
</dependency>
136135
<dependency>
137136
<groupId>org.mockito</groupId>
138137
<artifactId>mockito-core</artifactId>
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.jackrabbit.oak.commons.collections;
20+
21+
import org.apache.commons.collections4.iterators.LazyIteratorChain;
22+
23+
import java.util.Iterator;
24+
import java.util.Objects;
25+
26+
/**
27+
* Utility methods for {@link Iterable} conversions.
28+
*/
29+
public class IterableUtils {
30+
31+
private IterableUtils() {
32+
// no instances for you
33+
}
34+
35+
/**
36+
* Combines two iterables into a single iterable.
37+
* <p>
38+
* The returned iterable has an iterator that traverses the elements in {@code a},
39+
* followed by the elements in {@code b}. The source iterators are not polled until necessary.
40+
* <p>
41+
* The returned iterable's iterator supports {@code remove()} when the corresponding
42+
* input iterator supports it.
43+
*
44+
* @param <E> the element type
45+
* @param a the first iterable, may not be null
46+
* @param b the second iterable, may not be null
47+
* @return a new iterable, combining the provided iterables
48+
* @throws NullPointerException if either of the provided iterables is null
49+
*/
50+
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> a,
51+
final Iterable<? extends E> b) {
52+
return chainedIterable(new Iterable[] {a, b});
53+
}
54+
55+
/**
56+
* Combines three iterables into a single iterable.
57+
* <p>
58+
* The returned iterable has an iterator that traverses the elements in {@code a},
59+
* followed by the elements in {@code b} and {@code c}. The source
60+
* iterators are not polled until necessary.
61+
* <p>
62+
* The returned iterable's iterator supports {@code remove()} when the corresponding
63+
* input iterator supports it.
64+
*
65+
* @param <E> the element type
66+
* @param a the first iterable, may not be null
67+
* @param b the second iterable, may not be null
68+
* @param c the third iterable, may not be null
69+
* @return a new iterable, combining the provided iterables
70+
* @throws NullPointerException if either of the provided iterables is null
71+
*/
72+
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> a,
73+
final Iterable<? extends E> b,
74+
final Iterable<? extends E> c) {
75+
return chainedIterable(new Iterable[] {a, b, c});
76+
}
77+
78+
/**
79+
* Combines four iterables into a single iterable.
80+
* <p>
81+
* The returned iterable has an iterator that traverses the elements in {@code a},
82+
* followed by the elements in {@code b}, {@code c} and {@code d}. The source
83+
* iterators are not polled until necessary.
84+
* <p>
85+
* The returned iterable's iterator supports {@code remove()} when the corresponding
86+
* input iterator supports it.
87+
*
88+
* @param <E> the element type
89+
* @param a the first iterable, may not be null
90+
* @param b the second iterable, may not be null
91+
* @param c the third iterable, may not be null
92+
* @param d the fourth iterable, may not be null
93+
* @return a new iterable, combining the provided iterables
94+
* @throws NullPointerException if either of the provided iterables is null
95+
*/
96+
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> a,
97+
final Iterable<? extends E> b,
98+
final Iterable<? extends E> c,
99+
final Iterable<? extends E> d) {
100+
return chainedIterable(new Iterable[] {a, b, c, d});
101+
}
102+
103+
/**
104+
* Combines the provided iterables into a single iterable.
105+
* <p>
106+
* The returned iterable has an iterator that traverses the elements in the order
107+
* of the arguments, i.e. iterables[0], iterables[1], .... The source iterators
108+
* are not polled until necessary.
109+
* <p>
110+
* The returned iterable's iterator supports {@code remove()} when the corresponding
111+
* input iterator supports it.
112+
*
113+
* @param <E> the element type
114+
* @param iterables the iterables to combine, may not be null
115+
* @return a new iterable, combining the provided iterables
116+
* @throws NullPointerException if either of the provided iterables is null
117+
*/
118+
@SafeVarargs
119+
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E>... iterables) {
120+
Objects.requireNonNull(iterables);
121+
return org.apache.commons.collections4.IterableUtils.chainedIterable(iterables);
122+
}
123+
124+
/**
125+
* Creates an {@code Iterable} that chains multiple {@code Iterable} instances into a single {@code Iterable}.
126+
* <p>
127+
* The returned {@code Iterable} will iterate over all elements of the first {@code Iterable},
128+
* then all elements of the second, and so on.
129+
*
130+
* @param <E> the type of elements returned by the iterator
131+
* @param iterables an {@code Iterable} of {@code Iterable} instances to be chained
132+
* @return an {@code Iterable} that provides a single view of all elements in the input {@code Iterable} instances
133+
* @throws NullPointerException if the input {@code Iterable} or any of its elements are null
134+
*/
135+
public static <E> Iterable<E> chainedIterable(final Iterable<? extends Iterable<? extends E>> iterables) {
136+
Objects.requireNonNull(iterables);
137+
return () -> new LazyIteratorChain<>() {
138+
private final Iterator<? extends Iterable<? extends E>> iterator = iterables.iterator();
139+
140+
protected Iterator<? extends E> nextIterator(int count) {
141+
return iterator.hasNext() ? iterator.next().iterator() : null;
142+
}
143+
};
144+
}
145+
}

oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/collections/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* Utilities for Java collections and streams.
2222
*/
2323
@Internal(since = "1.0.0")
24-
@Version("2.0.0")
24+
@Version("2.1.0")
2525
package org.apache.jackrabbit.oak.commons.collections;
2626
import org.apache.jackrabbit.oak.commons.annotations.Internal;
2727
import org.osgi.annotation.versioning.Version;
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.jackrabbit.oak.commons.collections;
20+
21+
import org.junit.Assert;
22+
import org.junit.Test;
23+
24+
import java.util.Arrays;
25+
import java.util.Collections;
26+
import java.util.Iterator;
27+
import java.util.List;
28+
29+
/**
30+
* Unit tests for the {@link IterableUtils} class.
31+
* <p>
32+
* This class contains test cases to verify the functionality of the methods
33+
* in the {@link IterableUtils} class.
34+
*/
35+
public class IterableUtilsTest {
36+
37+
38+
@Test
39+
public void testTwoChainedIterable() {
40+
List<Integer> list1 = Arrays.asList(1, 2, 3);
41+
List<Integer> list2 = Arrays.asList(4, 5);
42+
43+
Iterable<Integer> chained = IterableUtils.chainedIterable(list1, list2);
44+
45+
Iterator<Integer> iterator = chained.iterator();
46+
List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5);
47+
for (Integer value : expected) {
48+
Assert.assertTrue(iterator.hasNext());
49+
Assert.assertEquals(value, iterator.next());
50+
}
51+
Assert.assertFalse(iterator.hasNext());
52+
}
53+
54+
@Test
55+
public void testThreeChainedIterable() {
56+
List<Integer> list1 = Arrays.asList(1, 2, 3);
57+
List<Integer> list2 = Arrays.asList(4, 5);
58+
List<Integer> list3 = Arrays.asList(6, 7, 8, 9);
59+
60+
Iterable<Integer> chained = IterableUtils.chainedIterable(list1, list2, list3);
61+
62+
Iterator<Integer> iterator = chained.iterator();
63+
List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
64+
for (Integer value : expected) {
65+
Assert.assertTrue(iterator.hasNext());
66+
Assert.assertEquals(value, iterator.next());
67+
}
68+
Assert.assertFalse(iterator.hasNext());
69+
}
70+
71+
@Test
72+
public void testChainedIterable() {
73+
List<Integer> list1 = Arrays.asList(1, 2, 3);
74+
List<Integer> list2 = Arrays.asList(4, 5);
75+
List<Integer> list3 = Arrays.asList(6, 7, 8, 9);
76+
77+
Iterable<Iterable<Integer>> iterables = Arrays.asList(list1, list2, list3);
78+
Iterable<Integer> chained = IterableUtils.chainedIterable(iterables);
79+
80+
Iterator<Integer> iterator = chained.iterator();
81+
List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
82+
for (Integer value : expected) {
83+
Assert.assertTrue(iterator.hasNext());
84+
Assert.assertEquals(value, iterator.next());
85+
}
86+
Assert.assertFalse(iterator.hasNext());
87+
}
88+
89+
@Test
90+
public void testFourChainedIterable() {
91+
List<Integer> list1 = Arrays.asList(1, 2, 3);
92+
List<Integer> list2 = Arrays.asList(4, 5);
93+
List<Integer> list3 = Arrays.asList(6, 7, 8, 9);
94+
List<Integer> list4 = Arrays.asList(10, 11, 12, 13);
95+
96+
Iterable<Integer> chained = IterableUtils.chainedIterable(list1, list2, list3, list4);
97+
98+
Iterator<Integer> iterator = chained.iterator();
99+
List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
100+
for (Integer value : expected) {
101+
Assert.assertTrue(iterator.hasNext());
102+
Assert.assertEquals(value, iterator.next());
103+
}
104+
Assert.assertFalse(iterator.hasNext());
105+
}
106+
107+
@Test
108+
public void testChainedIterableVaragrs() {
109+
List<Integer> list1 = Arrays.asList(1, 2, 3);
110+
List<Integer> list2 = Arrays.asList(4, 5);
111+
List<Integer> list3 = Arrays.asList(6, 7, 8, 9);
112+
List<Integer> list4 = Arrays.asList(10, 11, 12, 13);
113+
List<Integer> list5 = Arrays.asList(14, 15, 16);
114+
115+
Iterable<Integer> chained = IterableUtils.chainedIterable(list1, list2, list3, list4, list5);
116+
117+
Iterator<Integer> iterator = chained.iterator();
118+
List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
119+
for (Integer value : expected) {
120+
Assert.assertTrue(iterator.hasNext());
121+
Assert.assertEquals(value, iterator.next());
122+
}
123+
Assert.assertFalse(iterator.hasNext());
124+
}
125+
126+
@Test
127+
public void testChainedIterableEmpty() {
128+
Iterable<Iterable<Integer>> iterables = Collections.emptyList();
129+
Iterable<Integer> chained = IterableUtils.chainedIterable(iterables);
130+
131+
Iterator<Integer> iterator = chained.iterator();
132+
Assert.assertFalse(iterator.hasNext());
133+
}
134+
135+
@Test
136+
public void testChainedIterableSingle() {
137+
List<Integer> list = Arrays.asList(1, 2, 3);
138+
Iterable<Iterable<Integer>> iterables = Collections.singletonList(list);
139+
Iterable<Integer> chained = IterableUtils.chainedIterable(iterables);
140+
141+
Iterator<Integer> iterator = chained.iterator();
142+
List<Integer> expected = Arrays.asList(1, 2, 3);
143+
for (Integer value : expected) {
144+
Assert.assertTrue(iterator.hasNext());
145+
Assert.assertEquals(value, iterator.next());
146+
}
147+
Assert.assertFalse(iterator.hasNext());
148+
}
149+
150+
@Test
151+
public void testChainedIterableNullElement() {
152+
List<Integer> list1 = Arrays.asList(1, 2, 3);
153+
List<Integer> list2 = null;
154+
List<Integer> list3 = Arrays.asList(6, 7, 8, 9);
155+
156+
Iterable<Iterable<Integer>> iterables = Arrays.asList(list1, list2, list3);
157+
Iterable<Integer> chained = IterableUtils.chainedIterable(iterables);
158+
159+
Iterator<Integer> iterator = chained.iterator();
160+
List<Integer> expected = Arrays.asList(1, 2, 3);
161+
for (Integer value : expected) {
162+
Assert.assertTrue(iterator.hasNext());
163+
Assert.assertEquals(value, iterator.next());
164+
}
165+
166+
// now next iterator should be null
167+
Assert.assertThrows(NullPointerException.class, iterator::hasNext);
168+
}
169+
}

0 commit comments

Comments
 (0)