added paginated set functionality

This commit is contained in:
Adrian Cole 2012-06-24 11:47:49 -07:00
parent 01e27603f1
commit 763572f8ee
3 changed files with 265 additions and 0 deletions

View File

@ -0,0 +1,103 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.collect;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import com.google.common.collect.ForwardingSet;
import com.google.common.collect.ImmutableSet;
/**
* An {@code Set} that can be continued
*
* @author Adrian Cole
*/
@Beta
public class PaginatedSet<T> extends ForwardingSet<T> {
public static <T> PaginatedSet<T> copyOf(Iterable<T> contents) {
return new PaginatedSet<T>(contents, null);
}
public static <T> PaginatedSet<T> copyOfWithMarker(Iterable<T> contents, String marker) {
return new PaginatedSet<T>(contents, marker);
}
private final Set<T> contents;
private final String marker;
protected PaginatedSet(Iterable<T> contents, @Nullable String marker) {
this.contents = ImmutableSet.<T> copyOf(checkNotNull(contents, "contents"));
this.marker = marker;
}
/**
* If there is a next marker, then the set is incomplete and you should issue another command to
* retrieve the rest, setting the option {@code marker} to this value
*
* @return next marker, or null if list is complete
*/
@Nullable
public String getNextMarker() {
return marker;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hashCode(contents, marker);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PaginatedSet<?> other = PaginatedSet.class.cast(obj);
return Objects.equal(this.contents, other.contents) && Objects.equal(this.marker, other.marker);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return Objects.toStringHelper(this).add("contents", contents).add("marker", marker).toString();
}
@Override
protected Set<T> delegate() {
return contents;
}
}

View File

@ -0,0 +1,86 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.collect;
import java.util.Iterator;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.collect.AbstractIterator;
/**
* Utilities for using {@link PaginatedSet}s.
*
* @author Adrian Cole, Jeremy Whitlock
*/
@Beta
public class PaginatedSets {
/**
*
* @param initial
* the initial set of data
* @param markerToNext
* produces the next set based on the marker
*
* @return iterable of users fitting the criteria
*/
public static <T> Iterable<T> lazyContinue(final PaginatedSet<T> initial,
final Function<String, PaginatedSet<T>> markerToNext) {
if (initial.getNextMarker() == null)
return initial;
return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return new AbstractIterator<T>() {
private PaginatedSet<T> response = initial;
private Iterator<T> iterator = response.iterator();
/**
* {@inheritDoc}
*/
@Override
protected T computeNext() {
while (true) {
if (iterator == null) {
response = markerToNext.apply(response.getNextMarker());
iterator = response.iterator();
}
if (iterator.hasNext()) {
return iterator.next();
}
if (response.getNextMarker() == null) {
return endOfData();
}
iterator = null;
}
}
};
}
@Override
public String toString() {
return "lazyContinue(" + markerToNext.toString() + ")";
}
};
}
}

View File

@ -0,0 +1,76 @@
package org.jclouds.collect;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import org.easymock.EasyMock;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code PaginatedSets}.
*
* @author Adrian Cole
*/
@Test(testName = "PaginatedSetsTest")
public class PaginatedSetsTest {
@SuppressWarnings("unchecked")
@Test
public void testSinglePageResultReturnsSame() {
PaginatedSet<String> initial = PaginatedSet.copyOf(ImmutableSet.of("foo", "bar"));
Function<String, PaginatedSet<String>> markerToNext = createMock(Function.class);
EasyMock.replay(markerToNext);
Assert.assertSame(PaginatedSets.lazyContinue(initial, markerToNext), initial);
EasyMock.verify(markerToNext);
}
@SuppressWarnings("unchecked")
@Test
public void testMultiPage2Pages() {
PaginatedSet<String> initial = PaginatedSet.copyOfWithMarker(ImmutableSet.of("foo", "bar"), "MARKER1");
Function<String, PaginatedSet<String>> markerToNext = createMock(Function.class);
expect(markerToNext.apply("MARKER1")).andReturn(
PaginatedSet.copyOfWithMarker(ImmutableSet.of("boo", "baz"), null));
EasyMock.replay(markerToNext);
Assert.assertEquals(ImmutableSet.copyOf(PaginatedSets.lazyContinue(initial, markerToNext)), ImmutableSet.of(
"foo", "bar", "boo", "baz"));
EasyMock.verify(markerToNext);
}
@SuppressWarnings("unchecked")
@Test
public void testMultiPage3Pages() {
PaginatedSet<String> initial = PaginatedSet.copyOfWithMarker(ImmutableSet.of("foo", "bar"), "MARKER1");
Function<String, PaginatedSet<String>> markerToNext = createMock(Function.class);
expect(markerToNext.apply("MARKER1")).andReturn(
PaginatedSet.copyOfWithMarker(ImmutableSet.of("boo", "baz"), "MARKER2"));
expect(markerToNext.apply("MARKER2")).andReturn(
PaginatedSet.copyOfWithMarker(ImmutableSet.of("ham", "cheeze"), null));
EasyMock.replay(markerToNext);
Assert.assertEquals(ImmutableSet.copyOf(PaginatedSets.lazyContinue(initial, markerToNext)), ImmutableSet.of(
"foo", "bar", "boo", "baz", "ham", "cheeze"));
EasyMock.verify(markerToNext);
}
}