Skip to content

Commit cb64ccd

Browse files
committed
Merge pull request #318 from mziccard/move-list-result
Rename ListResult and move to core module
2 parents 33bfb1e + 26471e6 commit cb64ccd

15 files changed

Lines changed: 206 additions & 264 deletions

File tree

gcloud-java-storage/src/main/java/com/google/gcloud/storage/ListResult.java renamed to gcloud-java-core/src/main/java/com/google/gcloud/Page.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,38 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.google.gcloud.storage;
17+
package com.google.gcloud;
1818

1919
/**
20-
* Interface for Google Cloud storage list result.
20+
* Interface for Google Cloud paginated results.
21+
*
22+
* <p>
23+
* A typical {@code Page} usage:
24+
* <pre> {@code
25+
* Page<T> page = ...; // get a Page<T> instance
26+
* while (page != null) {
27+
* for (T value : page.values()) {
28+
* // do something with value
29+
* }
30+
* page = page.nextPage();
31+
* }
32+
* }</pre>
2133
*/
22-
public interface ListResult<T> extends Iterable<T> {
34+
public interface Page<T> {
35+
36+
/**
37+
* Returns the values contained in this page.
38+
*/
39+
Iterable<T> values();
2340

2441
/**
2542
* Returns the cursor for the nextPage or {@code null} if no more results.
2643
*/
2744
String nextPageCursor();
2845

2946
/**
30-
* Returns the results of the nextPage or {@code null} if no more result.
47+
* Returns the next page of results or {@code null} if no more result.
3148
*/
32-
ListResult<T> nextPage();
49+
Page<T> nextPage();
3350

3451
}

gcloud-java-storage/src/main/java/com/google/gcloud/storage/BaseListResult.java renamed to gcloud-java-core/src/main/java/com/google/gcloud/PageImpl.java

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,63 +14,66 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.google.gcloud.storage;
17+
package com.google.gcloud;
1818

1919
import java.io.Serializable;
2020
import java.util.Collections;
21-
import java.util.Iterator;
2221
import java.util.Objects;
2322

2423
/**
25-
* Base implementation for Google Cloud storage list result.
24+
* Base implementation for Google Cloud paginated results.
2625
*/
27-
public class BaseListResult<T extends Serializable> implements ListResult<T>, Serializable {
26+
public class PageImpl<T> implements Page<T>, Serializable {
2827

29-
private static final long serialVersionUID = -6937287874908527950L;
28+
private static final long serialVersionUID = 3914827379823557934L;
3029

3130
private final String cursor;
3231
private final Iterable<T> results;
3332
private final NextPageFetcher<T> pageFetcher;
3433

35-
public interface NextPageFetcher<T extends Serializable> extends Serializable {
36-
ListResult<T> nextPage();
34+
public interface NextPageFetcher<T> extends Serializable {
35+
Page<T> nextPage();
3736
}
3837

39-
public BaseListResult(NextPageFetcher<T> pageFetcher, String cursor, Iterable<T> results) {
38+
/**
39+
* Creates a {@code PageImpl} object. In order for the object to be serializable the {@code
40+
* results} parameter must be serializable.
41+
*/
42+
public PageImpl(NextPageFetcher<T> pageFetcher, String cursor, Iterable<T> results) {
4043
this.pageFetcher = pageFetcher;
4144
this.cursor = cursor;
4245
this.results = results;
4346
}
4447

48+
@Override
49+
public Iterable<T> values() {
50+
return results == null ? Collections.EMPTY_LIST : results;
51+
}
52+
4553
@Override
4654
public String nextPageCursor() {
4755
return cursor;
4856
}
4957

5058
@Override
51-
public ListResult<T> nextPage() {
59+
public Page<T> nextPage() {
5260
if (cursor == null || pageFetcher == null) {
5361
return null;
5462
}
5563
return pageFetcher.nextPage();
5664
}
5765

58-
@Override
59-
public Iterator<T> iterator() {
60-
return results == null ? Collections.<T>emptyIterator() : results.iterator();
61-
}
62-
6366
@Override
6467
public int hashCode() {
6568
return Objects.hash(cursor, results);
6669
}
6770

6871
@Override
6972
public boolean equals(Object obj) {
70-
if (!(obj instanceof BaseListResult)) {
73+
if (!(obj instanceof PageImpl)) {
7174
return false;
7275
}
73-
BaseListResult<?> other = (BaseListResult<?>) obj;
76+
PageImpl<?> other = (PageImpl<?>) obj;
7477
return Objects.equals(cursor, other.cursor)
7578
&& Objects.equals(results, other.results);
7679
}

gcloud-java-storage/src/test/java/com/google/gcloud/storage/BaseListResultTest.java renamed to gcloud-java-core/src/test/java/com/google/gcloud/PageImplTest.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.google.gcloud.storage;
17+
package com.google.gcloud;
1818

1919
import static org.junit.Assert.assertEquals;
2020

@@ -24,24 +24,23 @@
2424

2525
import java.util.Collections;
2626

27-
public class BaseListResultTest {
27+
public class PageImplTest {
2828

2929
@Test
30-
public void testListResult() throws Exception {
30+
public void testPage() throws Exception {
3131
ImmutableList<String> values = ImmutableList.of("1", "2");
32-
final BaseListResult<String> nextResult =
33-
new BaseListResult<>(null, "c", Collections.<String>emptyList());
34-
BaseListResult.NextPageFetcher<String> fetcher = new BaseListResult.NextPageFetcher<String>() {
32+
final PageImpl<String> nextResult =
33+
new PageImpl<>(null, "c", Collections.<String>emptyList());
34+
PageImpl.NextPageFetcher<String> fetcher = new PageImpl.NextPageFetcher<String>() {
3535

3636
@Override
37-
public BaseListResult<String> nextPage() {
37+
public PageImpl<String> nextPage() {
3838
return nextResult;
3939
}
4040
};
41-
BaseListResult<String> result = new BaseListResult<>(fetcher, "c", values);
41+
PageImpl<String> result = new PageImpl<>(fetcher, "c", values);
4242
assertEquals(nextResult, result.nextPage());
4343
assertEquals("c", result.nextPageCursor());
44-
assertEquals(values, ImmutableList.copyOf(result.iterator()));
45-
44+
assertEquals(values, ImmutableList.copyOf(result.values().iterator()));
4645
}
4746
}

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.google.gcloud.AuthCredentials;
2020
import com.google.gcloud.AuthCredentials.ServiceAccountAuthCredentials;
21+
import com.google.gcloud.Page;
2122
import com.google.gcloud.RetryParams;
2223
import com.google.gcloud.spi.StorageRpc.Tuple;
2324
import com.google.gcloud.storage.Blob;
@@ -213,8 +214,12 @@ String parse(String... args) {
213214
public void run(Storage storage, String bucketName) {
214215
if (bucketName == null) {
215216
// list buckets
216-
for (BucketInfo b : storage.list()) {
217-
System.out.println(b);
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();
218223
}
219224
} else {
220225
// list a bucket's blobs
@@ -223,8 +228,12 @@ public void run(Storage storage, String bucketName) {
223228
System.out.println("No such bucket");
224229
return;
225230
}
226-
for (Blob b : bucket.list()) {
227-
System.out.println(b.info());
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();
228237
}
229238
}
230239
}

gcloud-java-storage/src/main/java/com/google/gcloud/storage/BlobListResult.java

Lines changed: 0 additions & 77 deletions
This file was deleted.

gcloud-java-storage/src/main/java/com/google/gcloud/storage/Bucket.java

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,24 @@
1919
import static com.google.common.base.Preconditions.checkArgument;
2020
import static com.google.common.base.Preconditions.checkNotNull;
2121

22+
import com.google.common.base.Function;
2223
import com.google.common.base.MoreObjects;
24+
import com.google.common.collect.Iterators;
25+
import com.google.gcloud.PageImpl;
26+
import com.google.gcloud.Page;
2327
import com.google.gcloud.storage.Storage.BlobSourceOption;
2428
import com.google.gcloud.storage.Storage.BlobTargetOption;
2529
import com.google.gcloud.storage.Storage.BlobWriteOption;
2630
import com.google.gcloud.storage.Storage.BucketSourceOption;
2731
import com.google.gcloud.storage.Storage.BucketTargetOption;
28-
import java.io.InputStream;
2932

33+
import java.io.IOException;
34+
import java.io.InputStream;
35+
import java.io.ObjectInputStream;
36+
import java.io.Serializable;
3037
import java.util.ArrayList;
3138
import java.util.Collections;
39+
import java.util.Iterator;
3240
import java.util.List;
3341
import java.util.Objects;
3442

@@ -46,6 +54,71 @@ public final class Bucket {
4654
private final Storage storage;
4755
private final BucketInfo info;
4856

57+
private static class BlobPageFetcher implements PageImpl.NextPageFetcher<Blob> {
58+
59+
private static final long serialVersionUID = 3221100177471323801L;
60+
61+
private final StorageOptions options;
62+
private final Page<BlobInfo> infoPage;
63+
64+
BlobPageFetcher(StorageOptions options, Page<BlobInfo> infoPage) {
65+
this.options = options;
66+
this.infoPage = infoPage;
67+
}
68+
69+
@Override
70+
public Page<Blob> nextPage() {
71+
Page<BlobInfo> nextInfoPage = infoPage.nextPage();
72+
return new PageImpl<Blob>(new BlobPageFetcher(options, nextInfoPage),
73+
nextInfoPage.nextPageCursor(), new LazyBlobIterable(options, nextInfoPage.values()));
74+
}
75+
}
76+
77+
private static class LazyBlobIterable implements Iterable<Blob>, Serializable {
78+
79+
private static final long serialVersionUID = -3092290247725378832L;
80+
81+
private final StorageOptions options;
82+
private Iterable<BlobInfo> infoIterable;
83+
private transient Storage storage;
84+
85+
public LazyBlobIterable(StorageOptions options, Iterable<BlobInfo> infoIterable) {
86+
this.options = options;
87+
this.infoIterable = infoIterable;
88+
this.storage = options.service();
89+
}
90+
91+
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
92+
in.defaultReadObject();
93+
this.storage = options.service();
94+
}
95+
96+
@Override
97+
public Iterator<Blob> iterator() {
98+
return Iterators.transform(infoIterable.iterator(), new Function<BlobInfo, Blob>() {
99+
@Override
100+
public Blob apply(BlobInfo blobInfo) {
101+
return new Blob(storage, blobInfo);
102+
}
103+
});
104+
}
105+
106+
@Override
107+
public int hashCode() {
108+
return Objects.hash(options, infoIterable);
109+
}
110+
111+
@Override
112+
public boolean equals(Object obj) {
113+
if (!(obj instanceof LazyBlobIterable)) {
114+
return false;
115+
}
116+
LazyBlobIterable other = (LazyBlobIterable) obj;
117+
return Objects.equals(options, other.options)
118+
&& Objects.equals(infoIterable, other.infoIterable);
119+
}
120+
}
121+
49122
/**
50123
* Constructs a {@code Bucket} object for the provided {@code BucketInfo}. The storage service is
51124
* used to issue requests.
@@ -134,8 +207,11 @@ public boolean delete(BucketSourceOption... options) {
134207
* @param options options for listing blobs
135208
* @throws StorageException upon failure
136209
*/
137-
public ListResult<Blob> list(Storage.BlobListOption... options) {
138-
return new BlobListResult(storage, storage.list(info.name(), options));
210+
public Page<Blob> list(Storage.BlobListOption... options) {
211+
Page<BlobInfo> infoPage = storage.list(info.name(), options);
212+
StorageOptions storageOptions = storage.options();
213+
return new PageImpl<>(new BlobPageFetcher(storageOptions, infoPage), infoPage.nextPageCursor(),
214+
new LazyBlobIterable(storageOptions, infoPage.values()));
139215
}
140216

141217
/**

0 commit comments

Comments
 (0)