Skip to content

Commit 7a72399

Browse files
committed
Add iterateAll method to Page, update example and snippet
1 parent 0e32a4b commit 7a72399

File tree

5 files changed

+91
-22
lines changed

5 files changed

+91
-22
lines changed

gcloud-java-core/src/main/java/com/google/gcloud/Page.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,30 @@
1616

1717
package com.google.gcloud;
1818

19+
import java.util.Iterator;
20+
1921
/**
2022
* Interface for Google Cloud paginated results.
2123
*
2224
* <p>
23-
* A typical {@code Page} usage:
25+
* Use {@code Page} to iterate through all values (also in next pages):
26+
* <pre> {@code
27+
* Page<T> page = ...; // get a Page<T> instance
28+
* Iterator<T> iterator = page.iterateAll();
29+
* while (iterator.hasNext()) {
30+
* T value = iterator.next();
31+
* // do something with value
32+
* }}</pre>
33+
* <p>
34+
* Or handle pagination explicitly:
2435
* <pre> {@code
2536
* Page<T> page = ...; // get a Page<T> instance
2637
* while (page != null) {
2738
* for (T value : page.values()) {
2839
* // do something with value
2940
* }
3041
* page = page.nextPage();
31-
* }
32-
* }</pre>
42+
* }}</pre>
3343
*/
3444
public interface Page<T> {
3545

@@ -38,6 +48,12 @@ public interface Page<T> {
3848
*/
3949
Iterable<T> values();
4050

51+
/**
52+
* Returns an iterator for all values, possibly also in the next pages. Once current page's values
53+
* are traversed the iterator fetches next page, if any.
54+
*/
55+
Iterator<T> iterateAll();
56+
4157
/**
4258
* Returns the cursor for the nextPage or {@code null} if no more results.
4359
*/

gcloud-java-core/src/main/java/com/google/gcloud/PageImpl.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616

1717
package com.google.gcloud;
1818

19+
import com.google.common.collect.AbstractIterator;
20+
1921
import java.io.Serializable;
2022
import java.util.Collections;
23+
import java.util.Iterator;
2124
import java.util.Objects;
2225

2326
/**
@@ -35,6 +38,33 @@ public interface NextPageFetcher<T> extends Serializable {
3538
Page<T> nextPage();
3639
}
3740

41+
static class PageIterator<T> extends AbstractIterator<T> {
42+
43+
private Iterator<T> currentPageIterator;
44+
private Page<T> currentPage;
45+
46+
PageIterator(Page<T> currentPage) {
47+
this.currentPageIterator = currentPage.values().iterator();
48+
this.currentPage = currentPage;
49+
}
50+
51+
@Override
52+
protected T computeNext() {
53+
if (currentPageIterator.hasNext()) {
54+
return currentPageIterator.next();
55+
}
56+
Page<T> nextPage = currentPage.nextPage();
57+
if (nextPage != null) {
58+
currentPage = nextPage;
59+
currentPageIterator = currentPage.values().iterator();
60+
if (currentPageIterator.hasNext()) {
61+
return currentPageIterator.next();
62+
}
63+
}
64+
return endOfData();
65+
}
66+
}
67+
3868
/**
3969
* Creates a {@code PageImpl} object. In order for the object to be serializable the {@code
4070
* results} parameter must be serializable.
@@ -50,6 +80,11 @@ public Iterable<T> values() {
5080
return results == null ? Collections.EMPTY_LIST : results;
5181
}
5282

83+
@Override
84+
public Iterator<T> iterateAll() {
85+
return new PageIterator<T>(this);
86+
}
87+
5388
@Override
5489
public String nextPageCursor() {
5590
return cursor;

gcloud-java-core/src/test/java/com/google/gcloud/PageImplTest.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,38 @@
2626

2727
public class PageImplTest {
2828

29+
private static final ImmutableList<String> VALUES = ImmutableList.of("1", "2");
30+
private static final ImmutableList<String> NEXT_VALUES = ImmutableList.of("3", "4");
31+
private static final ImmutableList<String> ALL_VALUES = ImmutableList.<String>builder()
32+
.addAll(VALUES)
33+
.addAll(NEXT_VALUES)
34+
.build();
35+
2936
@Test
30-
public void testPage() throws Exception {
31-
ImmutableList<String> values = ImmutableList.of("1", "2");
32-
final PageImpl<String> nextResult =
33-
new PageImpl<>(null, "c", Collections.<String>emptyList());
37+
public void testPage() {
38+
final PageImpl<String> nextResult = new PageImpl<>(null, "c", NEXT_VALUES);
3439
PageImpl.NextPageFetcher<String> fetcher = new PageImpl.NextPageFetcher<String>() {
35-
3640
@Override
3741
public PageImpl<String> nextPage() {
3842
return nextResult;
3943
}
4044
};
41-
PageImpl<String> result = new PageImpl<>(fetcher, "c", values);
45+
PageImpl<String> result = new PageImpl<>(fetcher, "c", VALUES);
4246
assertEquals(nextResult, result.nextPage());
4347
assertEquals("c", result.nextPageCursor());
44-
assertEquals(values, ImmutableList.copyOf(result.values().iterator()));
48+
assertEquals(VALUES, result.values());
49+
}
50+
51+
@Test
52+
public void testIterateAll() {
53+
final PageImpl<String> nextResult = new PageImpl<>(null, "c", NEXT_VALUES);
54+
PageImpl.NextPageFetcher<String> fetcher = new PageImpl.NextPageFetcher<String>() {
55+
@Override
56+
public PageImpl<String> nextPage() {
57+
return nextResult;
58+
}
59+
};
60+
PageImpl<String> result = new PageImpl<>(fetcher, "c", VALUES);
61+
assertEquals(ALL_VALUES, ImmutableList.copyOf(result.iterateAll()));
4562
}
4663
}

gcloud-java-examples/src/main/java/com/google/gcloud/examples/StorageExample.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import java.security.cert.CertificateException;
5454
import java.util.Arrays;
5555
import java.util.HashMap;
56+
import java.util.Iterator;
5657
import java.util.List;
5758
import java.util.Map;
5859
import java.util.concurrent.TimeUnit;
@@ -214,12 +215,9 @@ String parse(String... args) {
214215
public void run(Storage storage, String bucketName) {
215216
if (bucketName == null) {
216217
// list buckets
217-
Page<BucketInfo> bucketPage = storage.list();
218-
while (bucketPage != null) {
219-
for (BucketInfo b : bucketPage.values()) {
220-
System.out.println(b);
221-
}
222-
bucketPage = bucketPage.nextPage();
218+
Iterator<BucketInfo> bucketInfoIterator = storage.list().iterateAll();
219+
while (bucketInfoIterator.hasNext()) {
220+
System.out.println(bucketInfoIterator.next());
223221
}
224222
} else {
225223
// list a bucket's blobs
@@ -228,12 +226,9 @@ public void run(Storage storage, String bucketName) {
228226
System.out.println("No such bucket");
229227
return;
230228
}
231-
Page<Blob> blobPage = bucket.list();
232-
while (blobPage != null) {
233-
for (Blob b : blobPage.values()) {
234-
System.out.println(b.info());
235-
}
236-
blobPage = blobPage.nextPage();
229+
Iterator<Blob> blobIterator = bucket.list().iterateAll();
230+
while (blobIterator.hasNext()) {
231+
System.out.println(blobIterator.next().info());
237232
}
238233
}
239234
}

gcloud-java-storage/src/test/java/com/google/gcloud/storage/RemoteGcsHelperTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.io.InputStream;
3434
import java.nio.file.Files;
3535
import java.nio.file.Paths;
36+
import java.util.Iterator;
3637
import java.util.List;
3738
import java.util.UUID;
3839
import java.util.concurrent.ExecutionException;
@@ -90,6 +91,11 @@ public Page<BlobInfo> nextPage() {
9091
public Iterable<BlobInfo> values() {
9192
return BLOB_LIST;
9293
}
94+
95+
@Override
96+
public Iterator<BlobInfo> iterateAll() {
97+
return BLOB_LIST.iterator();
98+
}
9399
};
94100
private static String keyPath = "/does/not/exist/key." + UUID.randomUUID().toString() + ".json";
95101

0 commit comments

Comments
 (0)