diff --git a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/domain/PaginatedCollection.java b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/domain/PaginatedCollection.java new file mode 100644 index 0000000000..93df2de688 --- /dev/null +++ b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/domain/PaginatedCollection.java @@ -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 extends IterableWithMarker { + private Iterable resources; + private Iterable links; + private int totalEntries; + + protected PaginatedCollection(@Nullable Iterable resources, @Nullable Iterable links, int totalEntries) { + this.resources = resources != null ? resources : ImmutableSet. of(); + this.links = links != null ? links : ImmutableSet. of(); + this.totalEntries = totalEntries; + } + + @Override + public Iterator iterator() { + return resources.iterator(); + } + + /** + * links that relate to this collection + */ + public Iterable getLinks() { + return links; + } + + public int getTotalEntries() { + return totalEntries; + } + + public PaginationOptions nextPaginationOptions() { + return PaginationOptions.class.cast(nextMarker().get()); + } + + @Override + public Optional nextMarker() { + for (Link link: getLinks()) { + if (Link.Relation.NEXT == link.getRelation()) { + return Optional. of(toPaginationOptions(link)); + } + } + + return Optional.absent(); + } + + private Object toPaginationOptions(Link link) { + Multimap queryParams = queryParser().apply(link.getHref().getRawQuery()); + PaginationOptions paginationOptions = PaginationOptions.Builder.queryParameters(queryParams); + + return paginationOptions; + } +} diff --git a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/functions/DateParser.java b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/functions/DateParser.java new file mode 100644 index 0000000000..4537b0d0cf --- /dev/null +++ b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/functions/DateParser.java @@ -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 { + + 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); + } + +} diff --git a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/options/PaginationOptions.java b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/options/PaginationOptions.java new file mode 100644 index 0000000000..5b9a65e887 --- /dev/null +++ b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v2_0/options/PaginationOptions.java @@ -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 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. + *

+ * 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 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); + } + } +} diff --git a/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v2_0/CloudIdentityFallbacks.java b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v2_0/CloudIdentityFallbacks.java new file mode 100644 index 0000000000..c9a6fe72c7 --- /dev/null +++ b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v2_0/CloudIdentityFallbacks.java @@ -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> { + private static final PaginatedCollection EMPTY = new PaginatedCollection( + ImmutableSet. of(), ImmutableSet. of(), 0) { + }; + + @Override + public ListenableFuture> create(Throwable t) throws Exception { + return immediateFuture(createOrPropagate(t)); + } + + @Override + public PaginatedCollection createOrPropagate(Throwable t) throws Exception { + return valOnNotFoundOr404(EMPTY, t); + } + } +} diff --git a/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v2_0/options/PaginationOptionsTest.java b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v2_0/options/PaginationOptionsTest.java new file mode 100644 index 0000000000..3f2db9eea2 --- /dev/null +++ b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v2_0/options/PaginationOptionsTest.java @@ -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 queryParameters = ImmutableSetMultimap. 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 queryParameters = ImmutableSetMultimap. of( + "limit", "1", + "offset", "1", + "name", "foo"); + PaginationOptions options = queryParameters(queryParameters); + assertEquals(queryParameters, options.buildQueryParameters()); + } +} diff --git a/core/src/main/java/org/jclouds/http/options/BaseHttpRequestOptions.java b/core/src/main/java/org/jclouds/http/options/BaseHttpRequestOptions.java index 80d7dbdf28..1947c00bc3 100644 --- a/core/src/main/java/org/jclouds/http/options/BaseHttpRequestOptions.java +++ b/core/src/main/java/org/jclouds/http/options/BaseHttpRequestOptions.java @@ -20,6 +20,7 @@ package org.jclouds.http.options; import java.util.Collection; +import com.google.common.base.Objects; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; @@ -134,8 +135,9 @@ public class BaseHttpRequestOptions implements HttpRequestOptions { @Override public String toString() { - return "[formParameters=" + formParameters + ", headers=" + headers + ", pathSuffix=" + pathSuffix + ", payload=" - + payload + ", queryParameters=" + queryParameters + "]"; + return Objects.toStringHelper(this).omitNullValues().add("formParameters", formParameters) + .add("headers", headers).add("pathSuffix", pathSuffix).add("payload", payload) + .add("queryParameters", queryParameters).toString(); } }