Skip to content

Commit

Permalink
Split ListResult into interface and implementation. Add BlobListResul…
Browse files Browse the repository at this point in the history
…t for paginated list of Blobs. Add tests.
  • Loading branch information
mziccard committed Sep 22, 2015
1 parent 21fc90c commit d8fa7bb
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 59 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed 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 com.google.gcloud.storage;

import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.Objects;

/**
* Base implementation for Google Cloud storage list result.
*/
public class BaseListResult<T extends Serializable> implements ListResult<T>, Serializable {

private static final long serialVersionUID = -6937287874908527950L;

private final String cursor;
private final Iterable<T> results;
private final NextPageFetcher<T> pageFetcher;

public interface NextPageFetcher<T extends Serializable> extends Serializable {
ListResult<T> nextPage();
}

public BaseListResult(NextPageFetcher<T> pageFetcher, String cursor, Iterable<T> results) {
this.pageFetcher = pageFetcher;
this.cursor = cursor;
this.results = results;
}

@Override
public String nextPageCursor() {
return cursor;
}

@Override
public ListResult<T> nextPage() {
if (cursor == null || pageFetcher == null) {
return null;
}
return pageFetcher.nextPage();
}

@Override
public Iterator<T> iterator() {
return results == null ? Collections.<T>emptyIterator() : results.iterator();
}

@Override
public int hashCode() {
return Objects.hash(cursor, results);
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof BaseListResult)) {
return false;
}
BaseListResult<?> other = (BaseListResult<?>) obj;
return Objects.equals(cursor, other.cursor)
&& Objects.equals(results, other.results);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed 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 com.google.gcloud.storage;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
* Implementation of a paginated list of Google Cloud storage {@code Blob}.
*/
public class BlobListResult implements ListResult<Blob> {

private final ListResult<BlobInfo> infoList;
private final transient Storage storage;
private transient List<Blob> results;

public BlobListResult(Storage storage, ListResult<BlobInfo> infoList) {
this.storage = storage;
this.infoList = infoList;
this.results = null;
}

@Override
public String nextPageCursor() {
return infoList.nextPageCursor();
}

@Override
public ListResult<Blob> nextPage() {
ListResult<BlobInfo> nextPageInfoList = infoList.nextPage();
if (nextPageInfoList == null) {
return null;
}
return new BlobListResult(storage, nextPageInfoList);
}

@Override
public Iterator<Blob> iterator() {
if (results == null) {
this.results = new LinkedList<>();
for (Iterator<BlobInfo> it = infoList.iterator(); it.hasNext();) {
results.add(new Blob(storage, it.next()));
}
}
return results.iterator();
}

@Override
public int hashCode() {
return Objects.hash(infoList);
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof BlobListResult)) {
return false;
}
BlobListResult other = (BlobListResult) obj;
return Objects.equals(infoList, other.infoList);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,67 +16,28 @@

package com.google.gcloud.storage;


import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.Objects;

/**
* Google Cloud storage list result.
* Interface for Google Cloud storage list result.
*/
public final class ListResult<T extends Serializable> implements Iterable<T>, Serializable {

private static final long serialVersionUID = -6937287874908527950L;

private final String cursor;
private final Iterable<T> results;
private final NextPageFetcher<T> pageFetcher;

public interface NextPageFetcher<T extends Serializable> extends Serializable {
ListResult<T> nextPage();
}

public ListResult(NextPageFetcher<T> pageFetcher, String cursor, Iterable<T> results) {
this.pageFetcher = pageFetcher;
this.cursor = cursor;
this.results = results;
}
public interface ListResult<T> extends Iterable<T> {

/**
* Returns the cursor for the nextPage or {@code null} if no more results.
*
* @return the string cursor for next page
*/
public String nextPageCursor() {
return cursor;
}
public String nextPageCursor();

/**
* Returns the results of the nextPage or {@code null} if no more result.
*
* @return the {@code ListResult} object for the next page
*/
public ListResult<T> nextPage() {
if (cursor == null || pageFetcher == null) {
return null;
}
return pageFetcher.nextPage();
}

@Override
public Iterator<T> iterator() {
return results == null ? Collections.<T>emptyIterator() : results.iterator();
}
public ListResult<T> nextPage();

@Override
public int hashCode() {
return Objects.hash(cursor, results);
}
public Iterator<T> iterator();

@Override
public boolean equals(Object obj) {
if (!(obj instanceof ListResult)) {
return false;
}
ListResult<?> other = (ListResult<?>) obj;
return Objects.equals(cursor, other.cursor)
&& Objects.equals(results, other.results);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public StorageObject call() {
}

private static abstract class BasePageFetcher<T extends Serializable>
implements ListResult.NextPageFetcher<T> {
implements BaseListResult.NextPageFetcher<T> {

private static final long serialVersionUID = 8236329004030295223L;
protected final Map<StorageRpc.Option, ?> requestOptions;
Expand Down Expand Up @@ -234,7 +234,7 @@ public Tuple<String, Iterable<com.google.api.services.storage.model.Bucket>> cal
}
}, serviceOptions.retryParams(), EXCEPTION_HANDLER);
String cursor = result.x();
return new ListResult<>(new BucketPageFetcher(serviceOptions, cursor, optionsMap), cursor,
return new BaseListResult<>(new BucketPageFetcher(serviceOptions, cursor, optionsMap), cursor,
Iterables.transform(result.y(),
new Function<com.google.api.services.storage.model.Bucket, BucketInfo>() {
@Override
Expand All @@ -259,7 +259,7 @@ public Tuple<String, Iterable<StorageObject>> call() {
}
}, serviceOptions.retryParams(), EXCEPTION_HANDLER);
String cursor = result.x();
return new ListResult<>(new BlobPageFetcher(bucket, serviceOptions, cursor, optionsMap), cursor,
return new BaseListResult<>(new BlobPageFetcher(bucket, serviceOptions, cursor, optionsMap), cursor,
Iterables.transform(result.y(),
new Function<StorageObject, BlobInfo>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,21 @@

import java.util.Collections;

public class ListResultTest {
public class BaseListResultTest {

@Test
public void testListResult() throws Exception {
ImmutableList<String> values = ImmutableList.of("1", "2");
final ListResult<String> nextResult =
new ListResult<>(null, "c", Collections.<String>emptyList());
ListResult.NextPageFetcher<String> fetcher = new ListResult.NextPageFetcher<String>() {
final BaseListResult<String> nextResult =
new BaseListResult<>(null, "c", Collections.<String>emptyList());
BaseListResult.NextPageFetcher<String> fetcher = new BaseListResult.NextPageFetcher<String>() {

@Override
public ListResult<String> nextPage() {
public BaseListResult<String> nextPage() {
return nextResult;
}
};
ListResult<String> result = new ListResult<>(fetcher, "c", values);
BaseListResult<String> result = new BaseListResult<>(fetcher, "c", values);
assertEquals(nextResult, result.nextPage());
assertEquals("c", result.nextPageCursor());
assertEquals(values, ImmutableList.copyOf(result.iterator()));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed 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 com.google.gcloud.storage;

import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

import com.google.common.collect.ImmutableList;
import java.util.Iterator;

import org.junit.Before;
import org.junit.Test;

public class BlobListResultTest {

private static final Iterable<BlobInfo> FIRST_PAGE_RESULTS = ImmutableList.of(
BlobInfo.of("b1", "n1"),
BlobInfo.of("b2", "n2"));

private static final Iterable<BlobInfo> SECOND_PAGE_RESULTS = ImmutableList.of(
BlobInfo.of("b1", "n1"),
BlobInfo.of("b2", "n2"));

private BaseListResult<BlobInfo> firstPage;
private BaseListResult<BlobInfo> secondPage;
private Storage storage;
private BlobListResult blobListResult;

@Before
public void setUp() throws Exception {
firstPage = createStrictMock(BaseListResult.class);
secondPage = createStrictMock(BaseListResult.class);
storage = createStrictMock(Storage.class);
blobListResult = new BlobListResult(storage, firstPage);
}

@Test
public void testListResult() throws Exception {
expect(firstPage.iterator()).andReturn(FIRST_PAGE_RESULTS.iterator());
replay(firstPage);
Iterator<BlobInfo> firstPageIterator = FIRST_PAGE_RESULTS.iterator();
Iterator<Blob> blobListIterator = blobListResult.iterator();
while (blobListIterator.hasNext() && firstPageIterator.hasNext()) {
assertEquals(firstPageIterator.next(), blobListIterator.next().info());
}
assertFalse(blobListIterator.hasNext());
assertFalse(firstPageIterator.hasNext());
verify(firstPage);
}

@Test
public void testCursor() throws Exception {
expect(firstPage.nextPageCursor()).andReturn("c");
replay(firstPage);
assertEquals("c", blobListResult.nextPageCursor());
verify(firstPage);
}

@Test
public void testNextPage() throws Exception {
expect(firstPage.nextPage()).andReturn(secondPage);
expect(secondPage.iterator()).andReturn(SECOND_PAGE_RESULTS.iterator());
replay(firstPage);
replay(secondPage);
ListResult<Blob> nextPageResult = blobListResult.nextPage();
Iterator<BlobInfo> secondPageIterator = SECOND_PAGE_RESULTS.iterator();
Iterator<Blob> blobListIterator = nextPageResult.iterator();
while (blobListIterator.hasNext() && secondPageIterator.hasNext()) {
assertEquals(secondPageIterator.next(), blobListIterator.next().info());
}
assertFalse(blobListIterator.hasNext());
assertFalse(secondPageIterator.hasNext());
verify(firstPage);
verify(secondPage);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public class SerializationTest {
Collections.singletonList(BatchResponse.Result.of(true)),
Collections.<BatchResponse.Result<BlobInfo>>emptyList(),
Collections.<BatchResponse.Result<BlobInfo>>emptyList());
private static final ListResult<BlobInfo> LIST_RESULT =
new ListResult<>(null, "c", Collections.singletonList(BlobInfo.of("b", "n")));
private static final BaseListResult<BlobInfo> LIST_RESULT =
new BaseListResult<>(null, "c", Collections.singletonList(BlobInfo.of("b", "n")));
private static final Storage.BlobListOption BLOB_LIST_OPTIONS =
Storage.BlobListOption.maxResults(100);
private static final Storage.BlobSourceOption BLOB_SOURCE_OPTIONS =
Expand Down

0 comments on commit d8fa7bb

Please sign in to comment.