mirror of https://github.com/apache/jclouds.git
Merge pull request #1460 from rackspace/rax-pagination
PaginatedCollection for Rackspace style pagination.
This commit is contained in:
commit
b943a8c19f
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* 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.rackspace.cloudidentity.v2_0.domain;
|
||||||
|
|
||||||
|
import static org.jclouds.http.utils.Queries.queryParser;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.jclouds.collect.IterableWithMarker;
|
||||||
|
import org.jclouds.javax.annotation.Nullable;
|
||||||
|
import org.jclouds.openstack.v2_0.domain.Link;
|
||||||
|
import org.jclouds.rackspace.cloudidentity.v2_0.options.PaginationOptions;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for a paginated collection in Rackspace.
|
||||||
|
*
|
||||||
|
* @author Everett Toews
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
public class PaginatedCollection<T> extends IterableWithMarker<T> {
|
||||||
|
private Iterable<T> resources;
|
||||||
|
private Iterable<Link> links;
|
||||||
|
private int totalEntries;
|
||||||
|
|
||||||
|
protected PaginatedCollection(@Nullable Iterable<T> resources, @Nullable Iterable<Link> links, int totalEntries) {
|
||||||
|
this.resources = resources != null ? resources : ImmutableSet.<T> of();
|
||||||
|
this.links = links != null ? links : ImmutableSet.<Link> of();
|
||||||
|
this.totalEntries = totalEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<T> iterator() {
|
||||||
|
return resources.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* links that relate to this collection
|
||||||
|
*/
|
||||||
|
public Iterable<Link> getLinks() {
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalEntries() {
|
||||||
|
return totalEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PaginationOptions nextPaginationOptions() {
|
||||||
|
return PaginationOptions.class.cast(nextMarker().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Object> nextMarker() {
|
||||||
|
for (Link link: getLinks()) {
|
||||||
|
if (Link.Relation.NEXT == link.getRelation()) {
|
||||||
|
return Optional.<Object> of(toPaginationOptions(link));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object toPaginationOptions(Link link) {
|
||||||
|
Multimap<String, String> queryParams = queryParser().apply(link.getHref().getRawQuery());
|
||||||
|
PaginationOptions paginationOptions = PaginationOptions.Builder.queryParameters(queryParams);
|
||||||
|
|
||||||
|
return paginationOptions;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* 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.rackspace.cloudidentity.v2_0.functions;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.date.DateService;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a Date and return a yyyy-MM-dd String.
|
||||||
|
*
|
||||||
|
* @author Everett Toews
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class DateParser implements Function<Object, String> {
|
||||||
|
|
||||||
|
private final DateService dateService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
DateParser(DateService dateService) {
|
||||||
|
this.dateService = dateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String apply(Object input) {
|
||||||
|
checkArgument(checkNotNull(input, "input") instanceof Date, "This function is only valid for Dates!");
|
||||||
|
Date date = Date.class.cast(input);
|
||||||
|
|
||||||
|
return dateService.iso8601SecondsDateFormat(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/**
|
||||||
|
* 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.rackspace.cloudidentity.v2_0.options;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import org.jclouds.http.options.BaseHttpRequestOptions;
|
||||||
|
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options used to control paginated results (aka list commands).
|
||||||
|
*
|
||||||
|
* @author Everett Toews
|
||||||
|
*/
|
||||||
|
public class PaginationOptions extends BaseHttpRequestOptions {
|
||||||
|
public PaginationOptions queryParameters(Multimap<String, String> queryParams) {
|
||||||
|
checkNotNull(queryParams, "queryParams");
|
||||||
|
queryParameters.putAll(queryParams);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset is the starting point for the return data. Offset must be a multiple of the limit (or zero).
|
||||||
|
*/
|
||||||
|
public PaginationOptions offset(int offset) {
|
||||||
|
checkState(offset >= 0, "offset must be >= 0");
|
||||||
|
queryParameters.put("offset", String.valueOf(offset));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limit is the restriction on the maximum number of items for that type that can be returned.
|
||||||
|
* <p/>
|
||||||
|
* Note that list operations never return itemNotFound (404) faults.
|
||||||
|
*/
|
||||||
|
public PaginationOptions limit(int limit) {
|
||||||
|
checkState(limit >= 0, "limit must be >= 0");
|
||||||
|
checkState(limit <= 10000, "limit must be <= 10000");
|
||||||
|
queryParameters.put("limit", Integer.toString(limit));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name is a filter on the result set.
|
||||||
|
*/
|
||||||
|
public PaginationOptions name(String nameFilter) {
|
||||||
|
queryParameters.put("name", nameFilter);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
public static PaginationOptions queryParameters(Multimap<String, String> queryParams) {
|
||||||
|
PaginationOptions options = new PaginationOptions();
|
||||||
|
return options.queryParameters(queryParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see PaginationOptions#offset(int)
|
||||||
|
*/
|
||||||
|
public static PaginationOptions offset(int offset) {
|
||||||
|
PaginationOptions options = new PaginationOptions();
|
||||||
|
return options.offset(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see PaginationOptions#limit(int)
|
||||||
|
*/
|
||||||
|
public static PaginationOptions limit(int limit) {
|
||||||
|
PaginationOptions options = new PaginationOptions();
|
||||||
|
return options.limit(limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see PaginationOptions#name(String)
|
||||||
|
*/
|
||||||
|
public static PaginationOptions name(String name) {
|
||||||
|
PaginationOptions options = new PaginationOptions();
|
||||||
|
return options.name(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
* 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.rackspace.cloudidentity.v2_0;
|
||||||
|
|
||||||
|
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||||
|
import static org.jclouds.Fallbacks.valOnNotFoundOr404;
|
||||||
|
|
||||||
|
import org.jclouds.Fallback;
|
||||||
|
import org.jclouds.openstack.v2_0.domain.Link;
|
||||||
|
import org.jclouds.rackspace.cloudidentity.v2_0.domain.PaginatedCollection;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
public final class CloudIdentityFallbacks {
|
||||||
|
private CloudIdentityFallbacks() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class EmptyPaginatedCollectionOnNotFoundOr404 implements Fallback<PaginatedCollection<Object>> {
|
||||||
|
private static final PaginatedCollection<Object> EMPTY = new PaginatedCollection<Object>(
|
||||||
|
ImmutableSet.<Object> of(), ImmutableSet.<Link> of(), 0) {
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<PaginatedCollection<Object>> create(Throwable t) throws Exception {
|
||||||
|
return immediateFuture(createOrPropagate(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PaginatedCollection<Object> createOrPropagate(Throwable t) throws Exception {
|
||||||
|
return valOnNotFoundOr404(EMPTY, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* 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.rackspace.cloudidentity.v2_0.options;
|
||||||
|
|
||||||
|
import static org.jclouds.rackspace.cloudidentity.v2_0.options.PaginationOptions.Builder.limit;
|
||||||
|
import static org.jclouds.rackspace.cloudidentity.v2_0.options.PaginationOptions.Builder.name;
|
||||||
|
import static org.jclouds.rackspace.cloudidentity.v2_0.options.PaginationOptions.Builder.offset;
|
||||||
|
import static org.jclouds.rackspace.cloudidentity.v2_0.options.PaginationOptions.Builder.queryParameters;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableSetMultimap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Everett Toews
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "PaginationOptionsTest")
|
||||||
|
public class PaginationOptionsTest {
|
||||||
|
|
||||||
|
public void testQueryParameters() {
|
||||||
|
ImmutableSetMultimap<String, String> queryParameters = ImmutableSetMultimap.<String, String> of(
|
||||||
|
"limit", "1",
|
||||||
|
"offset", "1",
|
||||||
|
"name", "foo");
|
||||||
|
PaginationOptions options = new PaginationOptions().queryParameters(queryParameters);
|
||||||
|
assertEquals(queryParameters, options.buildQueryParameters());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMaxResults() {
|
||||||
|
int limit = 1;
|
||||||
|
PaginationOptions options = new PaginationOptions().limit(limit);
|
||||||
|
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("limit"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffset() {
|
||||||
|
int offset = 1;
|
||||||
|
PaginationOptions options = new PaginationOptions().offset(offset);
|
||||||
|
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("offset"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNameFilter() {
|
||||||
|
String nameFilter = "foo";
|
||||||
|
PaginationOptions options = new PaginationOptions().name(nameFilter);
|
||||||
|
assertEquals(ImmutableList.of("foo"), options.buildQueryParameters().get("name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMaxResultsStatic() {
|
||||||
|
int limit = 1;
|
||||||
|
PaginationOptions options = limit(limit);
|
||||||
|
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("limit"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffsetStatic() {
|
||||||
|
int offset = 1;
|
||||||
|
PaginationOptions options = offset(offset);
|
||||||
|
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("offset"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNameFilterStatic() {
|
||||||
|
String nameFilter = "foo";
|
||||||
|
PaginationOptions options = name(nameFilter);
|
||||||
|
assertEquals(ImmutableList.of("foo"), options.buildQueryParameters().get("name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testQueryParametersStatic() {
|
||||||
|
ImmutableSetMultimap<String, String> queryParameters = ImmutableSetMultimap.<String, String> of(
|
||||||
|
"limit", "1",
|
||||||
|
"offset", "1",
|
||||||
|
"name", "foo");
|
||||||
|
PaginationOptions options = queryParameters(queryParameters);
|
||||||
|
assertEquals(queryParameters, options.buildQueryParameters());
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ package org.jclouds.http.options;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.collect.LinkedHashMultimap;
|
import com.google.common.collect.LinkedHashMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
|
@ -134,8 +135,9 @@ public class BaseHttpRequestOptions implements HttpRequestOptions {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[formParameters=" + formParameters + ", headers=" + headers + ", pathSuffix=" + pathSuffix + ", payload="
|
return Objects.toStringHelper(this).omitNullValues().add("formParameters", formParameters)
|
||||||
+ payload + ", queryParameters=" + queryParameters + "]";
|
.add("headers", headers).add("pathSuffix", pathSuffix).add("payload", payload)
|
||||||
|
.add("queryParameters", queryParameters).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue