Issue 1011: introducing PagedIterable

This commit is contained in:
Adrian Cole 2012-07-15 22:45:12 -07:00
parent 248c6dcb39
commit 315d5fb3ef
74 changed files with 1920 additions and 929 deletions

View File

@ -24,8 +24,9 @@ import org.jclouds.cloudwatch.domain.Metric;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.features.MetricApi;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterables;
import org.jclouds.collect.PagedIterators;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
@ -46,18 +47,19 @@ public class CloudWatch {
* @return iterable of metrics fitting the criteria
*/
public static Iterable<Metric> listMetrics(final MetricApi metricApi, final ListMetricsOptions options) {
return PaginatedIterables.lazyContinue(metricApi.list(options), new Function<Object, PaginatedIterable<Metric>>() {
return Iterables.concat(PagedIterables.create(PagedIterators.advancing(metricApi.list(options),
new Function<Object, IterableWithMarker<Metric>>() {
@Override
public PaginatedIterable<Metric> apply(Object input) {
return metricApi.list(options.clone().afterMarker(input));
}
@Override
public IterableWithMarker<Metric> apply(Object input) {
return metricApi.list(options.clone().afterMarker(input));
}
@Override
public String toString() {
return "listMetrics(" + options + ")";
}
});
@Override
public String toString() {
return "listMetrics(" + options + ")";
}
})));
}
/**

View File

@ -26,7 +26,8 @@ import org.jclouds.cloudwatch.domain.Metric;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.concurrent.Timeout;
/**
@ -54,9 +55,9 @@ public interface MetricApi {
*
* @return the response object
*/
PaginatedIterable<Metric> list(ListMetricsOptions options);
IterableWithMarker<Metric> list(ListMetricsOptions options);
PaginatedIterable<Metric> list();
PagedIterable<Metric> list();
/**
* Gets statistics for the specified metric.

View File

@ -29,14 +29,17 @@ import org.jclouds.cloudwatch.domain.GetMetricStatistics;
import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse;
import org.jclouds.cloudwatch.domain.Metric;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.functions.MetricsToPagedIterable;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.cloudwatch.xml.GetMetricStatisticsResponseHandlerV2;
import org.jclouds.cloudwatch.xml.ListMetricsResponseHandler;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.Transform;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
@ -59,8 +62,9 @@ public interface MetricAsyncApi {
@POST
@Path("/")
@XMLResponseParser(ListMetricsResponseHandler.class)
@Transform(MetricsToPagedIterable.class)
@FormParams(keys = "Action", values = "ListMetrics")
ListenableFuture<? extends PaginatedIterable<Metric>> list();
ListenableFuture<? extends PagedIterable<Metric>> list();
/**
* @see MetricApi#list(ListMetricsOptions)
@ -69,7 +73,7 @@ public interface MetricAsyncApi {
@Path("/")
@XMLResponseParser(ListMetricsResponseHandler.class)
@FormParams(keys = "Action", values = "ListMetrics")
ListenableFuture<? extends PaginatedIterable<Metric>> list(ListMetricsOptions options);
ListenableFuture<? extends IterableWithMarker<Metric>> list(ListMetricsOptions options);
/**
* @see MetricApi#getMetricStatistics(GetMetricStatistics)

View File

@ -0,0 +1,65 @@
/**
* 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.cloudwatch.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import org.jclouds.cloudwatch.CloudWatchApi;
import org.jclouds.cloudwatch.domain.Metric;
import org.jclouds.cloudwatch.features.MetricApi;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Beta
public class MetricsToPagedIterable extends CallerArg0ToPagedIterable<Metric, MetricsToPagedIterable> {
private final CloudWatchApi api;
@Inject
protected MetricsToPagedIterable(CloudWatchApi api) {
this.api = checkNotNull(api, "api");
}
@Override
protected Function<Object, IterableWithMarker<Metric>> markerToNextForCallingArg0(final String arg0) {
final MetricApi metricApi = api.getMetricApiForRegion(arg0);
return new Function<Object, IterableWithMarker<Metric>>() {
@Override
public IterableWithMarker<Metric> apply(Object input) {
return metricApi.list(ListMetricsOptions.Builder.afterMarker(input.toString()));
}
@Override
public String toString() {
return "listMetricsInRegion(" + arg0 + ")";
}
};
}
}

View File

@ -40,7 +40,7 @@ public class ListMetricsOptions extends BaseHttpRequestOptions implements Clonea
private Set<Dimension> dimensions = Sets.newLinkedHashSet();
private String metricName;
private String namespace;
private Object nextToken;
private Object afterMarker;
/**
* The namespace to filter against.
@ -93,12 +93,12 @@ public class ListMetricsOptions extends BaseHttpRequestOptions implements Clonea
/**
* The token returned by a previous call to indicate that there is more data available.
*
* @param nextToken the next token indicating that there is more data available
* @param afterMarker the next token indicating that there is more data available
*
* @return this {@code Builder} object
*/
public ListMetricsOptions afterMarker(Object nextToken) {
this.nextToken = nextToken;
public ListMetricsOptions afterMarker(Object afterMarker) {
this.afterMarker = afterMarker;
return this;
}
@ -129,9 +129,9 @@ public class ListMetricsOptions extends BaseHttpRequestOptions implements Clonea
}
}
// If nextToken isn't specified, don't include it
if (nextToken != null) {
formParameters.put("NextToken", nextToken.toString());
// If afterMarker isn't specified, don't include it
if (afterMarker != null) {
formParameters.put("NextToken", afterMarker.toString());
}
return formParameters.build();
@ -139,7 +139,7 @@ public class ListMetricsOptions extends BaseHttpRequestOptions implements Clonea
@Override
public ListMetricsOptions clone() {
return Builder.namespace(namespace).metricName(metricName).dimensions(dimensions).afterMarker(nextToken);
return Builder.namespace(namespace).metricName(metricName).dimensions(dimensions).afterMarker(afterMarker);
}
public static class Builder {
@ -175,8 +175,8 @@ public class ListMetricsOptions extends BaseHttpRequestOptions implements Clonea
/**
* @see ListMetricsOptions#afterMarker(String)
*/
public static ListMetricsOptions afterMarker(String nextToken) {
return new ListMetricsOptions().afterMarker(nextToken);
public static ListMetricsOptions afterMarker(Object afterMarker) {
return new ListMetricsOptions().afterMarker(afterMarker);
}
}

View File

@ -21,8 +21,8 @@ package org.jclouds.cloudwatch.xml;
import java.util.Set;
import org.jclouds.cloudwatch.domain.Metric;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
@ -36,7 +36,7 @@ import com.google.inject.Inject;
*
* @author Jeremy Whitlock
*/
public class ListMetricsResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<PaginatedIterable<Metric>> {
public class ListMetricsResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<IterableWithMarker<Metric>> {
private final MetricHandler metricHandler;
@ -54,8 +54,8 @@ public class ListMetricsResponseHandler extends ParseSax.HandlerForGeneratedRequ
* {@inheritDoc}
*/
@Override
public PaginatedIterable<Metric> getResult() {
return PaginatedIterables.forwardWithMarker(metrics, nextToken);
public IterableWithMarker<Metric> getResult() {
return IterableWithMarkers.from(metrics, nextToken);
}
/**

View File

@ -30,8 +30,8 @@ import org.jclouds.cloudwatch.domain.Metric;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.features.MetricApi;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.testng.Assert;
import org.testng.annotations.Test;
@ -58,7 +58,7 @@ public class CloudWatchTest {
CloudWatchApi api = createMock(CloudWatchApi.class);
MetricApi metricApi = createMock(MetricApi.class);
ListMetricsOptions options = new ListMetricsOptions();
PaginatedIterable<Metric> response = PaginatedIterables.forwardWithMarker(ImmutableSet.of(createMock(Metric.class)), null);
IterableWithMarker<Metric> response = IterableWithMarkers.from(ImmutableSet.of(createMock(Metric.class)), null);
expect(api.getMetricApiForRegion(null))
.andReturn(metricApi)
@ -84,8 +84,8 @@ public class CloudWatchTest {
CloudWatchApi api = createMock(CloudWatchApi.class);
MetricApi metricApi = createMock(MetricApi.class);
ListMetricsOptions options = new ListMetricsOptions();
PaginatedIterable<Metric> response1 = PaginatedIterables.forwardWithMarker(ImmutableSet.of(createMock(Metric.class)), "NEXTTOKEN");
PaginatedIterable<Metric> response2 = PaginatedIterables.forwardWithMarker(ImmutableSet.of(createMock(Metric.class)), null);
IterableWithMarker<Metric> response1 = IterableWithMarkers.from(ImmutableSet.of(createMock(Metric.class)), "NEXTTOKEN");
IterableWithMarker<Metric> response2 = IterableWithMarkers.from(ImmutableSet.of(createMock(Metric.class)), null);
// Using EasyMock.eq("") because EasyMock makes it impossible to pass null as a String value here
expect(api.getMetricApiForRegion(EasyMock.eq("")))

View File

@ -38,6 +38,8 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.collect.Iterables;
/**
* @author Jeremy Whitlock, Adrian Cole
*/
@ -72,8 +74,8 @@ public class MetricApiExpectTest extends BaseCloudWatchApiExpectTest {
CloudWatchApi apiWhenMetricsExist = requestSendsResponse(
listMetrics, listMetricsResponse);
assertEquals(apiWhenMetricsExist.getMetricApiForRegion(null).list().toString(),
"{elements=[Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}], marker=null}");
assertEquals(apiWhenMetricsExist.getMetricApiForRegion(null).list().get(0).toString(),
"[Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}]");
}
// TODO: this should really be an empty set
@ -85,9 +87,42 @@ public class MetricApiExpectTest extends BaseCloudWatchApiExpectTest {
CloudWatchApi apiWhenMetricsDontExist = requestSendsResponse(
listMetrics, listMetricsResponse);
apiWhenMetricsDontExist.getMetricApiForRegion(null).list();
apiWhenMetricsDontExist.getMetricApiForRegion(null).list().get(0);
}
public void testListMetrics2PagesWhenResponseIs2xx() throws Exception {
HttpResponse listMetricsResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/list_metrics_marker.xml", "text/xml")).build();
HttpRequest listMetrics2 = HttpRequest.builder()
.method("POST")
.endpoint("https://monitoring.us-east-1.amazonaws.com/")
.addHeader("Host", "monitoring.us-east-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=ListMetrics" +
"&NextToken=MARKER" +
"&Signature=RpBdQydXD1jQhEUnXoqT60NEuCP%2FZgdvO6Hf3uf%2Fwy0%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2010-08-01" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
HttpResponse listMetrics2Response = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/list_metrics.xml", "text/xml")).build();
CloudWatchApi apiWhenMetricsExist = requestsSendResponses(
listMetrics, listMetricsResponse, listMetrics2, listMetrics2Response);
assertEquals(Iterables.concat(apiWhenMetricsExist.getMetricApiForRegion(null).list()).toString(),
"[Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}, Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}]");
}
public void testListMetricsWithOptionsWhenResponseIs2xx() throws Exception {
HttpRequest listMetricsWithOptions =
HttpRequest.builder()
@ -124,7 +159,7 @@ public class MetricApiExpectTest extends BaseCloudWatchApiExpectTest {
.metricName(EC2Constants.MetricName.CPU_UTILIZATION)
.namespace("SOMENEXTTOKEN")
.afterMarker(Namespaces.EC2)).toString(),
"{elements=[Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}], marker=null}");
"[Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}]");
}
GetMetricStatistics stats = GetMetricStatistics.builder()

View File

@ -39,7 +39,7 @@ import org.jclouds.cloudwatch.domain.Statistics;
import org.jclouds.cloudwatch.domain.Unit;
import org.jclouds.cloudwatch.internal.BaseCloudWatchApiLiveTest;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.predicates.RetryablePredicate;
import org.testng.Assert;
import org.testng.annotations.Test;
@ -99,7 +99,7 @@ public class MetricApiLiveTest extends BaseCloudWatchApiLiveTest {
Assert.fail("Unable to gather the created CloudWatch data within the time (20m) allotted.");
}
PaginatedIterable<Metric> lmr = api().list(lmo);
IterableWithMarker<Metric> lmr = api().list(lmo);
Date endTime = new Date(metricTimestampInCloudWatch.getTime() + (60 * 1000)); // Pad a minute just in case
Date startTime = new Date(metricTimestampInCloudWatch.getTime() - (60 * 1000)); // Pad a minute just in case
@ -145,7 +145,7 @@ public class MetricApiLiveTest extends BaseCloudWatchApiLiveTest {
// TODO: change this test to retrieve pre-seeded custom metrics
@Test
protected void testGetMetricStatistics() {
PaginatedIterable<Metric> metricsResponse = api().list();
IterableWithMarker<Metric> metricsResponse = api().list(new ListMetricsOptions());
// Walk through all datapoints in all metrics until we find a metric datapoint that returns statistics
if (Iterables.size(metricsResponse) > 0) {
@ -195,14 +195,14 @@ public class MetricApiLiveTest extends BaseCloudWatchApiLiveTest {
@Test
protected void testListMetrics() {
PaginatedIterable<Metric> response;
IterableWithMarker<Metric> response;
String testNamespace = Namespaces.EC2;
String testMetricName = EC2Constants.MetricName.CPU_UTILIZATION;
String testDimensionName = EC2Constants.Dimension.INSTANCE_TYPE;
String testDimensionValue = "t1.micro";
// Test an empty request (pulls all stored metric options across all products)
response = api().list();
response = api().list(new ListMetricsOptions());
performDefaultMetricsTests(response);
@ -236,7 +236,7 @@ public class MetricApiLiveTest extends BaseCloudWatchApiLiveTest {
}
// Test with a NextToken, even if it's null
response = api().list(ListMetricsOptions.Builder.afterMarker(response.getNextMarker().toString()));
response = api().list(ListMetricsOptions.Builder.afterMarker(response.nextMarker().orNull()));
performDefaultMetricsTests(response);
@ -281,10 +281,10 @@ public class MetricApiLiveTest extends BaseCloudWatchApiLiveTest {
}
}
private void performDefaultMetricsTests(PaginatedIterable<Metric> response) {
private void performDefaultMetricsTests(IterableWithMarker<Metric> response) {
// If there are less than 500 metrics, NextToken should be null
if (Iterables.size(response) < 500) {
checkArgument(response.getNextMarker() == null,
checkArgument(!response.nextMarker().isPresent(),
"NextToken should be null for response with fewer than 500 metrics.");
}

View File

@ -0,0 +1,17 @@
<ListMetricsResponse xmlns="http://monitoring.amazonaws.com/doc/2010-08-01/">
<ListMetricsResult>
<Metrics>
<member>
<Dimensions>
<member>
<Name>InstanceId</Name>
<Value>i-689fcf0f</Value>
</member>
</Dimensions>
<MetricName>CPUUtilization</MetricName>
<Namespace>AWS/EC2</Namespace>
</member>
</Metrics>
<NextToken>MARKER</NextToken>
</ListMetricsResult>
</ListMetricsResponse>

View File

@ -21,23 +21,23 @@ package org.jclouds.collect;
import java.util.Iterator;
import com.google.common.annotations.Beta;
import com.google.common.collect.ForwardingObject;
import com.google.common.base.Optional;
/**
* An iterator which forwards all its method calls to another iterator.
* Subclasses should override one or more methods to modify the behavior of the
* backing iterable as desired per the <a
* An iterator which forwards all its method calls to another iterator. Subclasses should override
* one or more methods to modify the behavior of the backing iterable as desired per the <a
* href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
*
*
* @author Adrian Cole
*/
@Beta
public abstract class ForwardingPaginatedIterable<T> extends ForwardingObject implements PaginatedIterable<T> {
public abstract class ForwardingIterableWithMarker<T> extends IterableWithMarker<T> {
/** Constructor for use by subclasses. */
protected ForwardingPaginatedIterable() {}
protected ForwardingIterableWithMarker() {
}
@Override protected abstract PaginatedIterable<T> delegate();
protected abstract IterableWithMarker<T> delegate();
@Override
public Iterator<T> iterator() {
@ -45,8 +45,8 @@ public abstract class ForwardingPaginatedIterable<T> extends ForwardingObject im
}
@Override
public Object getNextMarker() {
return delegate().getNextMarker();
public Optional<Object> nextMarker() {
return delegate().nextMarker();
}
}

View File

@ -19,6 +19,8 @@
package org.jclouds.collect;
import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
/**
* An {@code Iterable} that can be continued
@ -26,14 +28,14 @@ import com.google.common.annotations.Beta;
* @author Adrian Cole
*/
@Beta
public interface PaginatedIterable<T> extends Iterable<T> {
public abstract class IterableWithMarker<T> extends FluentIterable<T> {
/**
* 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
* @return next marker, or absent if list is complete
*/
Object getNextMarker();
public abstract Optional<Object> nextMarker();
}

View File

@ -0,0 +1,88 @@
/**
* 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 elements 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.Iterator;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
/**
* Utilities for using {@link IterableWithMarker}s.
*
* @author Adrian Cole, Jeremy Whitlock
*/
@Beta
public class IterableWithMarkers {
/**
* Returns a paginated iterable containing the given elements and null marker.
*
*
* @throws NullPointerException
* if {@code elements} are null
*/
public static <T> IterableWithMarker<T> from(Iterable<T> elements) {
return from(elements, null);
}
/**
* Returns a paginated iterable containing the given elements and marker.
*
*
* @throws NullPointerException
* if {@code elements} are null
*/
public static <T> IterableWithMarker<T> from(final Iterable<T> elements, @Nullable final Object marker) {
return new ForwardingIterableWithMarker<T>() {
@Override
protected IterableWithMarker<T> delegate() {
return new ForwardedIterableWithMarker<T>(elements, marker);
}
};
}
private static final class ForwardedIterableWithMarker<T> extends IterableWithMarker<T> {
private final Iterable<T> elements;
private final Optional<Object> marker;
private ForwardedIterableWithMarker(Iterable<T> elements, @Nullable Object marker) {
this.elements = checkNotNull(elements, "elements");
this.marker = Optional.fromNullable(marker);
}
@Override
public Iterator<T> iterator() {
return elements.iterator();
}
@Override
public Optional<Object> nextMarker() {
return marker;
}
}
}

View File

@ -0,0 +1,44 @@
/**
* 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 com.google.common.annotations.Beta;
import com.google.common.collect.FluentIterable;
/**
* <pre>
* PagedIterator<StorageMetadata> blobs = blobstore.list(...).iterator();
* while (blobs.hasNext()) {
* FluentIterable<StorageMetadata> page = blobs.next();
* ProcessedResults results = process(page);
* if (results.shouldBeBookmarked() && blobs.nextMarker().isPresent()) {
* saveBookmark(blobs.nextMarker().get());
* }
* }
* </pre>
*
* @author Adrian Cole
*/
@Beta
public abstract class PagedIterable<T> extends FluentIterable<IterableWithMarker<T>> {
@Override
public abstract PagedIterator<T> iterator();
}

View File

@ -0,0 +1,49 @@
/**
* 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 current 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 com.google.common.annotations.Beta;
/**
* Utilities for using {@link PagedIterable}s.
*
* @author Adrian Cole
*/
@Beta
public class PagedIterables {
/**
*
* @param iterator
* how to advance pages
*
* @return iterable current data which continues if the user iterates beyond the first page
*/
public static <T> PagedIterable<T> create(final PagedIterator<T> iterator) {
return new PagedIterable<T>() {
@Override
public PagedIterator<T> iterator() {
return iterator;
}
};
}
}

View File

@ -0,0 +1,40 @@
/**
* 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 com.google.common.annotations.Beta;
import com.google.common.base.Optional;
import com.google.common.collect.AbstractIterator;
/**
*
* @author Adrian Cole
*/
@Beta
public abstract class PagedIterator<T> extends AbstractIterator<IterableWithMarker<T>> {
/**
* 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 absent if list is complete
*/
public abstract Optional<Object> nextMarker();
}

View File

@ -0,0 +1,184 @@
/**
* 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 current 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 com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
/**
* Utilities for using {@link PagedIterator}s.
*
* @author Adrian Cole
*/
@Beta
public class PagedIterators {
private static class AdvancingPagedIterator<T> extends PagedIterator<T> {
private final Function<Object, IterableWithMarker<T>> markerToNext;
private transient IterableWithMarker<T> current;
private transient boolean unread = true;
private AdvancingPagedIterator(IterableWithMarker<T> initial, Function<Object, IterableWithMarker<T>> markerToNext) {
this.current = checkNotNull(initial, "initial iterable");
this.markerToNext = checkNotNull(markerToNext, "marker to next iterable");
}
/**
* {@inheritDoc}
*/
@Override
protected IterableWithMarker<T> computeNext() {
if (unread)
try {
return current;
} finally {
unread = false;
}
else if (nextMarker().isPresent())
return current = markerToNext.apply(nextMarker().get());
else
return endOfData();
}
@Override
public Optional<Object> nextMarker() {
return current.nextMarker();
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hashCode(current, unread);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
AdvancingPagedIterator<?> other = AdvancingPagedIterator.class.cast(obj);
return Objects.equal(this.current, other.current) && Objects.equal(this.unread, other.unread);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return Objects.toStringHelper("").add("current", current).add("unread", unread).toString();
}
}
/**
*
* @param initial
* the initial set current data
* @param markerToNext
* produces the next set based on the marker
*
* @return iterable current data which continues if the user iterates beyond the first page
*/
public static <T> PagedIterator<T> advancing(IterableWithMarker<T> initial,
Function<Object, IterableWithMarker<T>> markerToNext) {
if (!initial.nextMarker().isPresent()) {
return of(initial);
}
return new AdvancingPagedIterator<T>(initial, markerToNext);
}
/**
*
* @param initial
* the initial set current data
* @return iterable current data which only contains the single element
*/
public static <T> PagedIterator<T> of(IterableWithMarker<T> initial) {
return new OnlyElementIterator<T>(initial);
}
private static class OnlyElementIterator<T> extends PagedIterator<T> {
private transient IterableWithMarker<T> onlyElement;
private transient boolean unread = true;
private OnlyElementIterator(IterableWithMarker<T> onlyElement) {
this.onlyElement = checkNotNull(onlyElement, "onlyElement");
}
/**
* {@inheritDoc}
*/
@Override
protected IterableWithMarker<T> computeNext() {
if (unread)
try {
return onlyElement;
} finally {
unread = false;
}
else
return endOfData();
}
@Override
public Optional<Object> nextMarker() {
return onlyElement.nextMarker();
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hashCode(onlyElement);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
OnlyElementIterator<?> other = OnlyElementIterator.class.cast(obj);
return Objects.equal(this.onlyElement, other.onlyElement) && Objects.equal(this.unread, other.unread);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return Objects.toStringHelper("").add("onlyElement", onlyElement).add("unread", unread).toString();
}
}
}

View File

@ -1,179 +0,0 @@
/**
* 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 elements 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.Iterator;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.ForwardingObject;
/**
* Utilities for using {@link PaginatedIterable}s.
*
* @author Adrian Cole, Jeremy Whitlock
*/
@Beta
public class PaginatedIterables {
/**
*
* @param initial
* the initial set elements data
* @param markerToNext
* produces the next set based on the marker
*
* @return iterable elements data which continues if the user iterates beyond the first page
*/
public static <T> Iterable<T> lazyContinue(final PaginatedIterable<T> initial,
final Function<Object, PaginatedIterable<T>> markerToNext) {
if (initial.getNextMarker() == null)
return initial;
return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return new AbstractIterator<T>() {
private PaginatedIterable<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 + ")";
}
};
}
/**
* Returns a paginated iterable containing the given elements and null marker.
*
*
* @throws NullPointerException
* if {@code elements} are null
*/
public static <T> PaginatedIterable<T> forward(Iterable<T> elements) {
return forwardWithMarker(elements, null);
}
/**
* Returns a paginated iterable containing the given elements and marker.
*
*
* @throws NullPointerException
* if {@code elements} are null
*/
public static <T> PaginatedIterable<T> forwardWithMarker(final Iterable<T> elements, @Nullable final Object marker) {
return new ForwardingPaginatedIterable<T>() {
@Override
protected PaginatedIterable<T> delegate() {
return new ForwardedPaginatedIterable<T>(elements, marker);
}
};
}
private static final class ForwardedPaginatedIterable<T> extends ForwardingObject implements PaginatedIterable<T> {
private final Iterable<T> elements;
private final Object marker;
@Override
protected Iterable<T> delegate() {
return elements;
}
private ForwardedPaginatedIterable(Iterable<T> elements, @Nullable Object marker) {
this.elements = checkNotNull(elements, "elements");
;
this.marker = marker;
}
@Override
public Iterator<T> iterator() {
return delegate().iterator();
}
@Override
public Object getNextMarker() {
return marker;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hashCode(elements, marker);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ForwardedPaginatedIterable<?> other = ForwardedPaginatedIterable.class.cast(obj);
return Objects.equal(this.elements, other.elements) && Objects.equal(this.marker, other.marker);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return Objects.toStringHelper("").add("elements", elements).add("marker", marker).toString();
}
}
}

View File

@ -0,0 +1,85 @@
/**
* 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.internal;
/**
* 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.
*/
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.collect.PagedIterables;
import org.jclouds.collect.PagedIterators;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Optional;
/**
* @author Adrian Cole
*/
@Beta
public abstract class CallerArg0ToPagedIterable<T, I extends CallerArg0ToPagedIterable<T, I>> implements
Function<IterableWithMarker<T>, PagedIterable<T>>, InvocationContext<I> {
private GeneratedHttpRequest request;
@Override
public PagedIterable<T> apply(IterableWithMarker<T> input) {
if (input.nextMarker() == null)
return PagedIterables.create(PagedIterators.of(input));
Optional<String> arg0Option = Optional.absent();
if (request.getCaller().get().getArgs() != null && request.getCaller().get().getArgs().length > 0) {
Object arg0 = request.getCaller().get().getArgs()[0];
if (arg0 != null)
arg0Option = Optional.of(arg0.toString());
}
final String arg0 = arg0Option.orNull();
return PagedIterables.create(PagedIterators.advancing(input, markerToNextForCallingArg0(arg0)));
}
protected abstract Function<Object, IterableWithMarker<T>> markerToNextForCallingArg0(String arg0);
@SuppressWarnings("unchecked")
@Override
public I setContext(HttpRequest request) {
this.request = GeneratedHttpRequest.class.cast(request);
return (I) this;
}
}

View File

@ -0,0 +1,32 @@
package org.jclouds.collect;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code IterableWithMarkers}.
*
* @author Adrian Cole
*/
@Test(testName = "IterableWithMarkersTest")
public class IterableWithMarkersTest {
@Test
public void testElementsEqual() {
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"));
Assert.assertEquals(initial.toImmutableSet(), ImmutableSet.of("foo", "bar"));
Assert.assertEquals(initial.nextMarker(), Optional.absent());
}
@Test
public void testMarkerEqual() {
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"), "MARKER");
Assert.assertEquals(initial.toImmutableSet(), ImmutableSet.of("foo", "bar"));
Assert.assertEquals(initial.nextMarker(), Optional.of("MARKER"));
}
}

View File

@ -0,0 +1,61 @@
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;
import com.google.common.collect.Iterables;
/**
* Tests behavior of {@code IterableWithMarkers}.
*
* @author Adrian Cole
*/
@Test(testName = "PagedIterablesTest")
public class PagedIterablesTest {
@SuppressWarnings("unchecked")
@Test
public void testSinglePageResultReturnsSame() {
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"));
Function<Object, IterableWithMarker<String>> markerToNext = createMock(Function.class);
EasyMock.replay(markerToNext);
PagedIterable<String> iterable = PagedIterables.create(PagedIterators.advancing(initial, markerToNext));
Assert.assertSame(iterable.get(0), initial);
EasyMock.verify(markerToNext);
}
@SuppressWarnings("unchecked")
@Test
public void testConcatPage3Pages() {
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"), "MARKER1");
Function<Object, IterableWithMarker<String>> markerToNext = createMock(Function.class);
expect(markerToNext.apply("MARKER1")).andReturn(
IterableWithMarkers.from(ImmutableSet.of("boo", "baz"), "MARKER2"));
expect(markerToNext.apply("MARKER2")).andReturn(IterableWithMarkers.from(ImmutableSet.of("ham", "cheeze"), null));
EasyMock.replay(markerToNext);
PagedIterable<String> iterable = PagedIterables.create(PagedIterators.advancing(initial, markerToNext));
Assert.assertEquals(ImmutableSet.copyOf(Iterables.concat(iterable)),
ImmutableSet.of("foo", "bar", "boo", "baz", "ham", "cheeze"));
EasyMock.verify(markerToNext);
}
}

View File

@ -0,0 +1,105 @@
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.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* Tests behavior of {@code IterableWithMarkers}.
*
* @author Adrian Cole
*/
@Test(testName = "PagedIteratorsTest")
public class PagedIteratorsTest {
@SuppressWarnings("unchecked")
@Test
public void testSinglePageResultReturnsSame() {
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"));
Function<Object, IterableWithMarker<String>> markerToNext = createMock(Function.class);
EasyMock.replay(markerToNext);
Assert.assertSame(PagedIterators.advancing(initial, markerToNext).next(), initial);
EasyMock.verify(markerToNext);
}
@SuppressWarnings("unchecked")
@Test
public void testMultiPage2Pages() {
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"), "MARKER1");
Function<Object, IterableWithMarker<String>> markerToNext = createMock(Function.class);
expect(markerToNext.apply("MARKER1")).andReturn(IterableWithMarkers.from(ImmutableSet.of("boo", "baz"), null));
EasyMock.replay(markerToNext);
Assert.assertEquals(ImmutableSet.copyOf(Iterables.concat(ImmutableSet.copyOf(PagedIterators.advancing(initial,
markerToNext)))), ImmutableSet.of("foo", "bar", "boo", "baz"));
EasyMock.verify(markerToNext);
}
@SuppressWarnings("unchecked")
@Test
public void testMultiPage3Pages() {
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"), "MARKER1");
Function<Object, IterableWithMarker<String>> markerToNext = createMock(Function.class);
expect(markerToNext.apply("MARKER1")).andReturn(
IterableWithMarkers.from(ImmutableSet.of("boo", "baz"), "MARKER2"));
expect(markerToNext.apply("MARKER2")).andReturn(IterableWithMarkers.from(ImmutableSet.of("ham", "cheeze"), null));
EasyMock.replay(markerToNext);
Assert.assertEquals(ImmutableSet.copyOf(Iterables.concat(ImmutableSet.copyOf(PagedIterators.advancing(initial,
markerToNext)))), ImmutableSet.of("foo", "bar", "boo", "baz", "ham", "cheeze"));
EasyMock.verify(markerToNext);
}
@SuppressWarnings("unchecked")
@Test
public void testMultiPage3PagesNextMarkerSetCorrectly() {
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"), "MARKER1");
Function<Object, IterableWithMarker<String>> markerToNext = createMock(Function.class);
IterableWithMarker<String> second = IterableWithMarkers.from(ImmutableSet.of("boo", "baz"), "MARKER2");
expect(markerToNext.apply("MARKER1")).andReturn(second);
IterableWithMarker<String> third = IterableWithMarkers.from(ImmutableSet.of("ham", "cheeze"), null);
expect(markerToNext.apply("MARKER2")).andReturn(third);
EasyMock.replay(markerToNext);
PagedIterator<String> iterator = PagedIterators.advancing(initial, markerToNext);
Assert.assertEquals(iterator.hasNext(), true);
Assert.assertEquals(iterator.nextMarker(), Optional.of("MARKER1"));
Assert.assertEquals(iterator.next(), initial);
Assert.assertEquals(iterator.hasNext(), true);
Assert.assertEquals(iterator.nextMarker(), Optional.of("MARKER2"));
Assert.assertEquals(iterator.next(), second);
Assert.assertEquals(iterator.hasNext(), true);
Assert.assertEquals(iterator.nextMarker(), Optional.absent());
Assert.assertEquals(iterator.next(), third);
Assert.assertEquals(iterator.hasNext(), false);
Assert.assertEquals(iterator.nextMarker(), Optional.absent());
EasyMock.verify(markerToNext);
}
}

View File

@ -1,76 +0,0 @@
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 PaginatedIterables}.
*
* @author Adrian Cole
*/
@Test(testName = "PaginatedIterablesTest")
public class PaginatedIterablesTest {
@SuppressWarnings("unchecked")
@Test
public void testSinglePageResultReturnsSame() {
PaginatedIterable<String> initial = PaginatedIterables.forward(ImmutableSet.of("foo", "bar"));
Function<Object, PaginatedIterable<String>> markerToNext = createMock(Function.class);
EasyMock.replay(markerToNext);
Assert.assertSame(PaginatedIterables.lazyContinue(initial, markerToNext), initial);
EasyMock.verify(markerToNext);
}
@SuppressWarnings("unchecked")
@Test
public void testMultiPage2Pages() {
PaginatedIterable<String> initial = PaginatedIterables.forwardWithMarker(ImmutableSet.of("foo", "bar"), "MARKER1");
Function<Object, PaginatedIterable<String>> markerToNext = createMock(Function.class);
expect(markerToNext.apply("MARKER1")).andReturn(
PaginatedIterables.forwardWithMarker(ImmutableSet.of("boo", "baz"), null));
EasyMock.replay(markerToNext);
Assert.assertEquals(ImmutableSet.copyOf(PaginatedIterables.lazyContinue(initial, markerToNext)), ImmutableSet.of(
"foo", "bar", "boo", "baz"));
EasyMock.verify(markerToNext);
}
@SuppressWarnings("unchecked")
@Test
public void testMultiPage3Pages() {
PaginatedIterable<String> initial = PaginatedIterables.forwardWithMarker(ImmutableSet.of("foo", "bar"), "MARKER1");
Function<Object, PaginatedIterable<String>> markerToNext = createMock(Function.class);
expect(markerToNext.apply("MARKER1")).andReturn(
PaginatedIterables.forwardWithMarker(ImmutableSet.of("boo", "baz"), "MARKER2"));
expect(markerToNext.apply("MARKER2")).andReturn(
PaginatedIterables.forwardWithMarker(ImmutableSet.of("ham", "cheeze"), null));
EasyMock.replay(markerToNext);
Assert.assertEquals(ImmutableSet.copyOf(PaginatedIterables.lazyContinue(initial, markerToNext)), ImmutableSet.of(
"foo", "bar", "boo", "baz", "ham", "cheeze"));
EasyMock.verify(markerToNext);
}
}

View File

@ -1,47 +0,0 @@
package org.jclouds.elb;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.elb.domain.LoadBalancer;
import org.jclouds.elb.features.LoadBalancerApi;
import org.jclouds.elb.options.ListLoadBalancersOptions;
import com.google.common.base.Function;
/**
* Utilities for using ELB.
*
* @author Adrian Cole
*/
public class ELB {
/**
* List loadBalancers based on the criteria in the {@link ListLoadBalancersOptions} passed in.
*
* @param loadBalancerApi
* the {@link LoadBalancerApi} to use for the request
* @param options
* the {@link ListLoadBalancersOptions} describing the ListLoadBalancers request
*
* @return iterable of loadBalancers fitting the criteria
*/
public static Iterable<LoadBalancer> listLoadBalancers(final LoadBalancerApi loadBalancerApi, final ListLoadBalancersOptions options) {
return PaginatedIterables.lazyContinue(loadBalancerApi.list(options), new Function<Object, PaginatedIterable<LoadBalancer>>() {
@Override
public PaginatedIterable<LoadBalancer> apply(Object input) {
return loadBalancerApi.list(options.clone().afterMarker(input));
}
@Override
public String toString() {
return "listLoadBalancers(" + options + ")";
}
});
}
public static Iterable<LoadBalancer> listLoadBalancers(LoadBalancerApi loadBalancerApi) {
return listLoadBalancers(loadBalancerApi, new ListLoadBalancersOptions());
}
}

View File

@ -20,7 +20,8 @@ package org.jclouds.elb.features;
import java.util.concurrent.TimeUnit;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.concurrent.Timeout;
import org.jclouds.elb.domain.Listener;
import org.jclouds.elb.domain.LoadBalancer;
@ -73,15 +74,15 @@ public interface LoadBalancerApi {
*
* @return the response object
*/
PaginatedIterable<LoadBalancer> list(ListLoadBalancersOptions options);
IterableWithMarker<LoadBalancer> list(ListLoadBalancersOptions options);
/**
* Lists the loadBalancers all load balancers
*
* @return the response object
*/
PaginatedIterable<LoadBalancer> list();
PagedIterable<LoadBalancer> list();
/**
* Deletes the specified LoadBalancer.
*

View File

@ -25,13 +25,15 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.elb.binders.BindAvailabilityZonesToIndexedFormParams;
import org.jclouds.elb.binders.BindListenersToFormParams;
import org.jclouds.elb.binders.BindSecurityGroupsToIndexedFormParams;
import org.jclouds.elb.binders.BindSubnetsToIndexedFormParams;
import org.jclouds.elb.domain.Listener;
import org.jclouds.elb.domain.LoadBalancer;
import org.jclouds.elb.functions.LoadBalancersToPagedIterable;
import org.jclouds.elb.options.ListLoadBalancersOptions;
import org.jclouds.elb.xml.CreateLoadBalancerResponseHandler;
import org.jclouds.elb.xml.DescribeLoadBalancersResultHandler;
@ -40,6 +42,7 @@ import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.Transform;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
@ -121,8 +124,9 @@ public interface LoadBalancerAsyncApi {
@POST
@Path("/")
@XMLResponseParser(DescribeLoadBalancersResultHandler.class)
@Transform(LoadBalancersToPagedIterable.class)
@FormParams(keys = "Action", values = "DescribeLoadBalancers")
ListenableFuture<PaginatedIterable<LoadBalancer>> list();
ListenableFuture<PagedIterable<LoadBalancer>> list();
/**
* @see LoadBalancerApi#list(ListLoadBalancersOptions)
@ -131,7 +135,7 @@ public interface LoadBalancerAsyncApi {
@Path("/")
@XMLResponseParser(DescribeLoadBalancersResultHandler.class)
@FormParams(keys = "Action", values = "DescribeLoadBalancers")
ListenableFuture<PaginatedIterable<LoadBalancer>> list(ListLoadBalancersOptions options);
ListenableFuture<IterableWithMarker<LoadBalancer>> list(ListLoadBalancersOptions options);
/**
* @see LoadBalancerApi#delete()

View File

@ -0,0 +1,65 @@
/**
* 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.elb.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
import org.jclouds.elb.ELBApi;
import org.jclouds.elb.domain.LoadBalancer;
import org.jclouds.elb.features.LoadBalancerApi;
import org.jclouds.elb.options.ListLoadBalancersOptions;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Beta
public class LoadBalancersToPagedIterable extends CallerArg0ToPagedIterable<LoadBalancer, LoadBalancersToPagedIterable> {
private final ELBApi api;
@Inject
protected LoadBalancersToPagedIterable(ELBApi api) {
this.api = checkNotNull(api, "api");
}
@Override
protected Function<Object, IterableWithMarker<LoadBalancer>> markerToNextForCallingArg0(final String arg0) {
final LoadBalancerApi loadBalancerApi = api.getLoadBalancerApiForRegion(arg0);
return new Function<Object, IterableWithMarker<LoadBalancer>>() {
@Override
public IterableWithMarker<LoadBalancer> apply(Object input) {
return loadBalancerApi.list(ListLoadBalancersOptions.Builder.afterMarker(input));
}
@Override
public String toString() {
return "listLoadBalancersInRegion(" + arg0 + ")";
}
};
}
}

View File

@ -33,6 +33,7 @@ import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.collect.PagedIterable;
import org.jclouds.concurrent.Futures;
import org.jclouds.elb.ELBAsyncApi;
import org.jclouds.elb.domain.LoadBalancer;
@ -83,11 +84,11 @@ public class ELBListLoadBalancersStrategy implements ListLoadBalancersStrategy {
public ListenableFuture<? extends Iterable<LoadBalancerInRegion>> apply(final String from) {
// TODO: ELB.listLoadBalancers
return Futures.compose(aapi.getLoadBalancerApiForRegion(from).list(),
new Function<Iterable<LoadBalancer>, Iterable<LoadBalancerInRegion>>() {
new Function<PagedIterable<LoadBalancer>, Iterable<LoadBalancerInRegion>>() {
@Override
public Iterable<LoadBalancerInRegion> apply(Iterable<LoadBalancer> input) {
return Iterables.transform(input,
public Iterable<LoadBalancerInRegion> apply(PagedIterable<LoadBalancer> input) {
return Iterables.transform(Iterables.concat(input),
new Function<LoadBalancer, LoadBalancerInRegion>() {
@Override

View File

@ -23,8 +23,8 @@ import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Set;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.elb.domain.LoadBalancer;
import org.jclouds.http.functions.ParseSax;
import org.xml.sax.Attributes;
@ -41,7 +41,7 @@ import com.google.inject.Inject;
* @author Adrian Cole
*/
public class DescribeLoadBalancersResultHandler extends
ParseSax.HandlerForGeneratedRequestWithResult<PaginatedIterable<LoadBalancer>> {
ParseSax.HandlerForGeneratedRequestWithResult<IterableWithMarker<LoadBalancer>> {
private final LoadBalancerHandler loadBalancerHandler;
@ -61,8 +61,8 @@ public class DescribeLoadBalancersResultHandler extends
* {@inheritDoc}
*/
@Override
public PaginatedIterable<LoadBalancer> getResult() {
return PaginatedIterables.forwardWithMarker(loadBalancers, marker);
public IterableWithMarker<LoadBalancer> getResult() {
return IterableWithMarkers.from(loadBalancers, marker);
}
/**

View File

@ -1,63 +0,0 @@
package org.jclouds.elb;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import org.easymock.EasyMock;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.elb.domain.LoadBalancer;
import org.jclouds.elb.features.LoadBalancerApi;
import org.jclouds.elb.options.ListLoadBalancersOptions;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* Tests behavior of {@code ELB}.
*
* @author Adrian Cole
*/
@Test(testName = "ELBTest")
public class ELBTest {
@Test
public void testSinglePageResult() throws Exception {
LoadBalancerApi loadBalancerApi = createMock(LoadBalancerApi.class);
ListLoadBalancersOptions options = new ListLoadBalancersOptions();
PaginatedIterable<LoadBalancer> response = PaginatedIterables.forward(ImmutableSet.of(createMock(LoadBalancer.class)));
expect(loadBalancerApi.list(options))
.andReturn(response)
.once();
EasyMock.replay(loadBalancerApi);
Assert.assertEquals(1, Iterables.size(ELB.listLoadBalancers(loadBalancerApi, options)));
}
@Test
public void testMultiPageResult() throws Exception {
LoadBalancerApi loadBalancerApi = createMock(LoadBalancerApi.class);
ListLoadBalancersOptions options = new ListLoadBalancersOptions();
PaginatedIterable<LoadBalancer> response1 = PaginatedIterables.forwardWithMarker(ImmutableSet.of(createMock(LoadBalancer.class)), "NEXTTOKEN");
PaginatedIterable<LoadBalancer> response2 = PaginatedIterables.forward(ImmutableSet.of(createMock(LoadBalancer.class)));
expect(loadBalancerApi.list(anyObject(ListLoadBalancersOptions.class)))
.andReturn(response1)
.once();
expect(loadBalancerApi.list(anyObject(ListLoadBalancersOptions.class)))
.andReturn(response2)
.once();
EasyMock.replay(loadBalancerApi);
Assert.assertEquals(2, Iterables.size(ELB.listLoadBalancers(loadBalancerApi, options)));
}
}

View File

@ -29,6 +29,7 @@ import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
@ -46,7 +47,7 @@ public class InstanceApiLiveTest extends BaseELBApiLiveTest {
@Test
protected void testListInstanceStates() {
for (LoadBalancer loadBalancer : context.getApi().getLoadBalancerApi().list()) {
for (LoadBalancer loadBalancer : Iterables.concat(context.getApi().getLoadBalancerApi().list())) {
Set<InstanceHealth> response = api().getHealthOfInstancesOfLoadBalancer(loadBalancer.getName());
for (InstanceHealth instanceState : response) {

View File

@ -25,6 +25,7 @@ import static org.testng.Assert.assertNull;
import java.util.TimeZone;
import org.jclouds.elb.ELBApi;
import org.jclouds.elb.domain.LoadBalancer;
import org.jclouds.elb.internal.BaseELBApiExpectTest;
import org.jclouds.elb.parse.DescribeLoadBalancersResponseTest;
import org.jclouds.elb.parse.GetLoadBalancerResponseTest;
@ -33,6 +34,9 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@ -106,9 +110,93 @@ public class LoadBalancerApiExpectTest extends BaseELBApiExpectTest {
ELBApi apiWhenExist = requestSendsResponse(
list, listResponse);
assertEquals(apiWhenExist.getLoadBalancerApi().list().toString(), new DescribeLoadBalancersResponseTest().expected().toString());
assertEquals(apiWhenExist.getLoadBalancerApi().list().get(0).toString(), new DescribeLoadBalancersResponseTest().expected().toString());
}
public void testList2PagesWhenResponseIs2xx() throws Exception {
HttpResponse listResponse1 = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/describe_loadbalancers_marker.xml", "text/xml")).build();
HttpRequest list2 = HttpRequest.builder()
.method("POST")
.endpoint("https://elasticloadbalancing.us-east-1.amazonaws.com/")
.addHeader("Host", "elasticloadbalancing.us-east-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=DescribeLoadBalancers" +
"&Marker=MARKER" +
"&Signature=%2FJttkIXuYljhZLJOPYyn%2BYIkDhD9skmePH3LYEnqmes%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2012-06-01" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
HttpResponse listResponse2 = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/describe_loadbalancers.xml", "text/xml")).build();
ELBApi apiWhenExist = requestsSendResponses(
list, listResponse1, list2, listResponse2);
LoadBalancer lb1 = new GetLoadBalancerResponseTest().expected().toBuilder().name("my-load-balancer-1").build();
LoadBalancer lb2 = new GetLoadBalancerResponseTest().expected();
assertEquals(ImmutableSet.copyOf(Iterables.concat(apiWhenExist.getLoadBalancerApi().list())), ImmutableSet.of(lb1, lb2));
}
public void testList2PagesWhenResponseIs2xxInEU() throws Exception {
HttpRequest list = HttpRequest.builder()
.method("POST")
.endpoint("https://elasticloadbalancing.eu-west-1.amazonaws.com/")
.addHeader("Host", "elasticloadbalancing.eu-west-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=DescribeLoadBalancers" +
"&Signature=%2FT6QECRsE52DT6mA7AkBy4%2Bdnvy4RXU3nNt56td0GTo%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2012-06-01" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
HttpResponse listResponse1 = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/describe_loadbalancers_marker.xml", "text/xml")).build();
HttpRequest list2 = HttpRequest.builder()
.method("POST")
.endpoint("https://elasticloadbalancing.eu-west-1.amazonaws.com/")
.addHeader("Host", "elasticloadbalancing.eu-west-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=DescribeLoadBalancers" +
"&Marker=MARKER" +
"&Signature=jiNCvpqj2fTKbput%2BhBtYMM6KpWAFzBeW20FyWeoyZw%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2012-06-01" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
HttpResponse listResponse2 = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/describe_loadbalancers.xml", "text/xml")).build();
ELBApi apiWhenExist = requestsSendResponses(list, listResponse1, list2, listResponse2);
LoadBalancer lb1 = new GetLoadBalancerResponseTest().expected().toBuilder().name("my-load-balancer-1").build();
LoadBalancer lb2 = new GetLoadBalancerResponseTest().expected();
assertEquals(ImmutableSet.copyOf(Iterables.concat(apiWhenExist.getLoadBalancerApiForRegion("eu-west-1").list())), ImmutableSet.of(lb1, lb2));
}
// TODO: this should really be an empty set
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testListWhenResponseIs404() throws Exception {

View File

@ -21,7 +21,9 @@ package org.jclouds.elb.features;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import org.jclouds.collect.PaginatedIterable;
import java.util.Set;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.elb.domain.ListenerWithPolicies;
import org.jclouds.elb.domain.LoadBalancer;
import org.jclouds.elb.internal.BaseELBApiLiveTest;
@ -29,6 +31,7 @@ import org.jclouds.elb.options.ListLoadBalancersOptions;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
@ -69,10 +72,26 @@ public class LoadBalancerApiLiveTest extends BaseELBApiLiveTest {
checkNotNull(listener.getSSLCertificateId(),
"While SSLCertificateId can be null for a ListenerWithPolicies, its Optional wrapper cannot.");
}
@Test
protected void testList() {
Set<LoadBalancer> response = ImmutableSet.copyOf(Iterables.concat(api().list()));
for (LoadBalancer loadBalancer : response) {
checkLoadBalancer(loadBalancer);
for (ListenerWithPolicies listener : loadBalancer.getListeners()) {
checkListener(listener);
}
}
if (Iterables.size(response) > 0) {
LoadBalancer loadBalancer = response.iterator().next();
Assert.assertEquals(api().get(loadBalancer.getName()), loadBalancer);
}
}
@Test
protected void testDescribeLoadBalancers() {
PaginatedIterable<LoadBalancer> response = api().list();
protected void testListWithOptions() {
IterableWithMarker<LoadBalancer> response = api().list(new ListLoadBalancersOptions());
for (LoadBalancer loadBalancer : response) {
checkLoadBalancer(loadBalancer);
@ -87,7 +106,7 @@ public class LoadBalancerApiLiveTest extends BaseELBApiLiveTest {
}
// Test with a Marker, even if it's null
response = api().list(ListLoadBalancersOptions.Builder.afterMarker(response.getNextMarker()));
response = api().list(ListLoadBalancersOptions.Builder.afterMarker(response.nextMarker().orNull()));
for (LoadBalancer loadBalancer : response) {
checkLoadBalancer(loadBalancer);
}

View File

@ -20,10 +20,10 @@ package org.jclouds.elb.loadbalancer;
import static org.testng.Assert.assertEquals;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PagedIterable;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.elb.ELBAsyncApi;
import org.jclouds.elb.ELBApi;
import org.jclouds.elb.ELBAsyncApi;
import org.jclouds.elb.domain.LoadBalancer;
import org.jclouds.loadbalancer.BaseLoadBalancerServiceLiveTest;
import org.jclouds.rest.RestContext;
@ -32,6 +32,7 @@ import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Iterables;
/**
*
@ -60,8 +61,8 @@ public class ELBLoadBalancerServiceLiveTest extends BaseLoadBalancerServiceLiveT
instanceIds.add(node.getProviderId());
}
PaginatedIterable<LoadBalancer> elbs = elbApi.getLoadBalancerApi().list();
for (LoadBalancer elb : elbs) {
PagedIterable<LoadBalancer> elbs = elbApi.getLoadBalancerApi().list();
for (LoadBalancer elb : Iterables.concat(elbs)) {
if (elb.getName().equals(group))
assertEquals(elb.getInstanceIds(), instanceIds.build());
}

View File

@ -22,8 +22,8 @@ import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.elb.domain.HealthCheck;
import org.jclouds.elb.domain.ListenerWithPolicies;
@ -45,17 +45,17 @@ public class DescribeLoadBalancersResponseTest extends BaseHandlerTest {
public void test() {
InputStream is = getClass().getResourceAsStream("/describe_loadbalancers.xml");
PaginatedIterable<LoadBalancer> expected = expected();
IterableWithMarker<LoadBalancer> expected = expected();
DescribeLoadBalancersResultHandler handler = injector.getInstance(DescribeLoadBalancersResultHandler.class);
PaginatedIterable<LoadBalancer> result = factory.create(handler).parse(is);
IterableWithMarker<LoadBalancer> result = factory.create(handler).parse(is);
assertEquals(result.toString(), expected.toString());
}
public PaginatedIterable<LoadBalancer> expected() {
return PaginatedIterables.forward(ImmutableSet.of(
public IterableWithMarker<LoadBalancer> expected() {
return IterableWithMarkers.from(ImmutableSet.of(
LoadBalancer.builder()
.name("my-load-balancer")
.createdTime(new SimpleDateFormatDateService().iso8601DateParse("2010-03-03T20:54:45.110Z"))

View File

@ -22,8 +22,8 @@ import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.elb.domain.HealthCheck;
import org.jclouds.elb.domain.ListenerWithPolicies;
@ -46,17 +46,17 @@ public class DescribeVPCLoadBalancersResponseTest extends BaseHandlerTest {
public void test() {
InputStream is = getClass().getResourceAsStream("/describe_loadbalancers_vpc.xml");
PaginatedIterable<LoadBalancer> expected = expected();
IterableWithMarker<LoadBalancer> expected = expected();
DescribeLoadBalancersResultHandler handler = injector.getInstance(DescribeLoadBalancersResultHandler.class);
PaginatedIterable<LoadBalancer> result = factory.create(handler).parse(is);
IterableWithMarker<LoadBalancer> result = factory.create(handler).parse(is);
assertEquals(result.toString(), expected.toString());
}
public PaginatedIterable<LoadBalancer> expected() {
return PaginatedIterables.forward(ImmutableSet.of(
public IterableWithMarker<LoadBalancer> expected() {
return IterableWithMarkers.from(ImmutableSet.of(
LoadBalancer.builder()
.name("tests")
.createdTime(new SimpleDateFormatDateService().iso8601DateParse("2012-07-08T19:54:24.190Z"))

View File

@ -0,0 +1,64 @@
<DescribeLoadBalancersResponse
xmlns="http://elasticloadbalancing.amazonaws.com/doc/2009-11-25/">
<DescribeLoadBalancersResult>
<LoadBalancerDescriptions>
<member>
<LoadBalancerName>my-load-balancer-1</LoadBalancerName>
<CreatedTime>2010-03-03T20:54:45.110Z</CreatedTime>
<DNSName>my-load-balancer-1400212309.us-east-1.elb.amazonaws.com</DNSName>
<HealthCheck>
<Interval>300</Interval>
<Target>HTTP:80/index.html</Target>
<HealthyThreshold>3</HealthyThreshold>
<Timeout>30</Timeout>
<UnhealthyThreshold>5</UnhealthyThreshold>
</HealthCheck>
<ListenerDescriptions>
<member>
<PolicyNames />
<Listener>
<Protocol>HTTP</Protocol>
<LoadBalancerPort>80</LoadBalancerPort>
<InstancePort>80</InstancePort>
</Listener>
</member>
<member>
<PolicyNames />
<Listener>
<Protocol>TCP</Protocol>
<LoadBalancerPort>443</LoadBalancerPort>
<InstancePort>443</InstancePort>
</Listener>
</member>
</ListenerDescriptions>
<Instances>
<member>
<InstanceId>i-5b33e630</InstanceId>
</member>
<member>
<InstanceId>i-8f26d7e4</InstanceId>
</member>
<member>
<InstanceId>i-5933e632</InstanceId>
</member>
</Instances>
<Policies>
<AppCookieStickinessPolicies>
<member>
<CookieName>MyCookie</CookieName>
<PolicyName>MyLoadBalancerPolicy</PolicyName>
</member>
</AppCookieStickinessPolicies>
<LBCookieStickinessPolicies />
</Policies>
<AvailabilityZones>
<member>us-east-1a</member>
</AvailabilityZones>
</member>
</LoadBalancerDescriptions>
<Marker>MARKER</Marker>
</DescribeLoadBalancersResult>
<ResponseMetadata>
<RequestId>10e2b9c9-3899-11df-a1e2-b5349194c035</RequestId>
</ResponseMetadata>
</DescribeLoadBalancersResponse>

View File

@ -1,43 +0,0 @@
package org.jclouds.iam;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.iam.domain.User;
import org.jclouds.iam.features.UserApi;
import org.jclouds.iam.options.ListUsersOptions;
import com.google.common.base.Function;
/**
* Utilities for using IAM.
*
* @author Adrian Cole
*/
public class IAM {
/**
* List users based on the criteria in the {@link ListUsersOptions} passed in.
*
* @param userApi
* the {@link UserApi} to use for the request
* @param options
* the {@link ListUsersOptions} describing the ListUsers request
*
* @return iterable of users fitting the criteria
*/
public static Iterable<User> list(final UserApi userApi, final ListUsersOptions options) {
return PaginatedIterables.lazyContinue(userApi.list(options), new Function<Object, PaginatedIterable<User>>() {
@Override
public PaginatedIterable<User> apply(Object input) {
return userApi.list(options.clone().afterMarker(input));
}
@Override
public String toString() {
return "listUsers(" + options + ")";
}
});
}
}

View File

@ -20,7 +20,8 @@ package org.jclouds.iam.features;
import java.util.concurrent.TimeUnit;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.concurrent.Timeout;
import org.jclouds.iam.domain.User;
import org.jclouds.iam.options.ListUsersOptions;
@ -62,7 +63,7 @@ public interface UserApi {
*
* @return the response object
*/
PaginatedIterable<User> list(ListUsersOptions options);
IterableWithMarker<User> list(ListUsersOptions options);
/**
* Lists the users that have the specified path prefix. If there are none, the action returns an
@ -70,6 +71,6 @@ public interface UserApi {
*
* @return the response object
*/
PaginatedIterable<User> list();
PagedIterable<User> list();
}

View File

@ -23,14 +23,17 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.iam.domain.User;
import org.jclouds.iam.functions.UsersToPagedIterable;
import org.jclouds.iam.options.ListUsersOptions;
import org.jclouds.iam.xml.ListUsersResultHandler;
import org.jclouds.iam.xml.UserHandler;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.Transform;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
@ -73,8 +76,9 @@ public interface UserAsyncApi {
@POST
@Path("/")
@XMLResponseParser(ListUsersResultHandler.class)
@Transform(UsersToPagedIterable.class)
@FormParams(keys = "Action", values = "ListUsers")
ListenableFuture<PaginatedIterable<User>> list();
ListenableFuture<PagedIterable<User>> list();
/**
* @see UserApi#list(ListUsersOptions)
@ -83,6 +87,6 @@ public interface UserAsyncApi {
@Path("/")
@XMLResponseParser(ListUsersResultHandler.class)
@FormParams(keys = "Action", values = "ListUsers")
ListenableFuture<PaginatedIterable<User>> list(ListUsersOptions options);
ListenableFuture<IterableWithMarker<User>> list(ListUsersOptions options);
}

View File

@ -0,0 +1,65 @@
/**
* 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.iam.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
import org.jclouds.iam.IAMApi;
import org.jclouds.iam.domain.User;
import org.jclouds.iam.features.UserApi;
import org.jclouds.iam.options.ListUsersOptions;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Beta
public class UsersToPagedIterable extends CallerArg0ToPagedIterable<User, UsersToPagedIterable> {
private final IAMApi api;
@Inject
protected UsersToPagedIterable(IAMApi api) {
this.api = checkNotNull(api, "api");
}
@Override
protected Function<Object, IterableWithMarker<User>> markerToNextForCallingArg0(String ignored) {
final UserApi userApi = api.getUserApi();
return new Function<Object, IterableWithMarker<User>>() {
@Override
public IterableWithMarker<User> apply(Object input) {
return userApi.list(ListUsersOptions.Builder.afterMarker(input.toString()));
}
@Override
public String toString() {
return "listUsers()";
}
};
}
}

View File

@ -20,8 +20,8 @@ package org.jclouds.iam.xml;
import java.util.Set;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.iam.domain.User;
import org.jclouds.util.SaxUtils;
@ -36,7 +36,7 @@ import com.google.inject.Inject;
*
* @author Adrian Cole
*/
public class ListUsersResultHandler extends ParseSax.HandlerForGeneratedRequestWithResult<PaginatedIterable<User>> {
public class ListUsersResultHandler extends ParseSax.HandlerForGeneratedRequestWithResult<IterableWithMarker<User>> {
private final UserHandler userHandler;
@ -54,8 +54,8 @@ public class ListUsersResultHandler extends ParseSax.HandlerForGeneratedRequestW
* {@inheritDoc}
*/
@Override
public PaginatedIterable<User> getResult() {
return PaginatedIterables.forwardWithMarker(users, afterMarker);
public IterableWithMarker<User> getResult() {
return IterableWithMarkers.from(users, afterMarker);
}
/**

View File

@ -1,63 +0,0 @@
package org.jclouds.iam;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import org.easymock.EasyMock;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.iam.domain.User;
import org.jclouds.iam.features.UserApi;
import org.jclouds.iam.options.ListUsersOptions;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* Tests behavior of {@code IAM}.
*
* @author Adrian Cole
*/
@Test(testName = "IAMTest")
public class IAMTest {
@Test
public void testSinglePageResult() throws Exception {
UserApi userApi = createMock(UserApi.class);
ListUsersOptions options = new ListUsersOptions();
PaginatedIterable<User> response = PaginatedIterables.forward(ImmutableSet.of(createMock(User.class)));
expect(userApi.list(options))
.andReturn(response)
.once();
EasyMock.replay(userApi);
Assert.assertEquals(1, Iterables.size(IAM.list(userApi, options)));
}
@Test
public void testMultiPageResult() throws Exception {
UserApi userApi = createMock(UserApi.class);
ListUsersOptions options = new ListUsersOptions();
PaginatedIterable<User> response1 = PaginatedIterables.forwardWithMarker(ImmutableSet.of(createMock(User.class)), "NEXTTOKEN");
PaginatedIterable<User> response2 = PaginatedIterables.forward(ImmutableSet.of(createMock(User.class)));
expect(userApi.list(anyObject(ListUsersOptions.class)))
.andReturn(response1)
.once();
expect(userApi.list(anyObject(ListUsersOptions.class)))
.andReturn(response2)
.once();
EasyMock.replay(userApi);
Assert.assertEquals(2, Iterables.size(IAM.list(userApi, options)));
}
}

View File

@ -33,6 +33,9 @@ import org.jclouds.iam.parse.ListUsersResponseTest;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@ -120,9 +123,37 @@ public class UserApiExpectTest extends BaseIAMApiExpectTest {
IAMApi apiWhenExist = requestSendsResponse(
list, listResponse);
assertEquals(apiWhenExist.getUserApi().list().toString(), new ListUsersResponseTest().expected().toString());
assertEquals(apiWhenExist.getUserApi().list().get(0).toString(), new ListUsersResponseTest().expected().toString());
}
public void testList2PagesWhenResponseIs2xx() throws Exception {
HttpResponse listResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/list_users_marker.xml", "text/xml")).build();
HttpRequest list2 = HttpRequest.builder()
.method("POST")
.endpoint("https://iam.amazonaws.com/")
.addHeader("Host", "iam.amazonaws.com")
.addFormParam("Action", "ListUsers")
.addFormParam("Marker", "MARKER")
.addFormParam("Signature", "LKYao6Hll%2FplLDqOcgbNuJ6DhmOw0tZl4Sf3pPY%2By00%3D")
.addFormParam("SignatureMethod", "HmacSHA256")
.addFormParam("SignatureVersion", "2")
.addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
.addFormParam("Version", "2010-05-08")
.addFormParam("AWSAccessKeyId", "identity").build();
HttpResponse list2Response = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/list_users.xml", "text/xml")).build();
IAMApi apiWhenExist = requestsSendResponses(list, listResponse, list2, list2Response);
assertEquals(ImmutableList.copyOf(Iterables.concat(apiWhenExist.getUserApi().list())),
ImmutableList.copyOf(Iterables.concat(new ListUsersResponseTest().expected(), new ListUsersResponseTest().expected())));
}
// TODO: this should really be an empty set
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testListWhenResponseIs404() throws Exception {
@ -132,7 +163,7 @@ public class UserApiExpectTest extends BaseIAMApiExpectTest {
IAMApi apiWhenDontExist = requestSendsResponse(
list, listResponse);
apiWhenDontExist.getUserApi().list();
apiWhenDontExist.getUserApi().list().get(0);
}
public void testListWithOptionsWhenResponseIs2xx() throws Exception {

View File

@ -20,7 +20,7 @@ package org.jclouds.iam.features;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.iam.domain.User;
import org.jclouds.iam.internal.BaseIAMApiLiveTest;
import org.jclouds.iam.options.ListUsersOptions;
@ -51,7 +51,7 @@ public class UserApiLiveTest extends BaseIAMApiLiveTest {
@Test
protected void testListUsers() {
PaginatedIterable<User> response = api().list();
IterableWithMarker<User> response = api().list().get(0);
for (User user : response) {
checkUser(user);
@ -63,7 +63,7 @@ public class UserApiLiveTest extends BaseIAMApiLiveTest {
}
// Test with a Marker, even if it's null
response = api().list(ListUsersOptions.Builder.afterMarker(response.getNextMarker()));
response = api().list(ListUsersOptions.Builder.afterMarker(response.nextMarker().orNull()));
for (User user : response) {
checkUser(user);
}

View File

@ -22,8 +22,8 @@ import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.iam.domain.User;
@ -42,17 +42,17 @@ public class ListUsersResponseTest extends BaseHandlerTest {
public void test() {
InputStream is = getClass().getResourceAsStream("/list_users.xml");
PaginatedIterable<User> expected = expected();
IterableWithMarker<User> expected = expected();
ListUsersResultHandler handler = injector.getInstance(ListUsersResultHandler.class);
PaginatedIterable<User> result = factory.create(handler).parse(is);
IterableWithMarker<User> result = factory.create(handler).parse(is);
assertEquals(result.toString(), expected.toString());
}
public PaginatedIterable<User> expected() {
return PaginatedIterables.forward(ImmutableSet.of(
public IterableWithMarker<User> expected() {
return IterableWithMarkers.from(ImmutableSet.of(
User.builder()
.path("/division_abc/subdivision_xyz/engineering/")
.name("Andrew")

View File

@ -0,0 +1,25 @@
<ListUsersResponse>
<ListUsersResult>
<Users>
<member>
<Path>/division_abc/subdivision_xyz/engineering/</Path>
<UserName>Andrew</UserName>
<UserId>AID2MAB8DPLSRHEXAMPLE</UserId>
<Arn>arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/engineering/Andrew</Arn>
<CreateDate>2009-03-06T21:47:48Z</CreateDate>
</member>
<member>
<Path>/division_abc/subdivision_xyz/engineering/</Path>
<UserName>Jackie</UserName>
<UserId>AIDIODR4TAW7CSEXAMPLE</UserId>
<Arn>arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/engineering/Jackie</Arn>
<CreateDate>2009-03-06T21:47:48Z</CreateDate>
</member>
</Users>
<Marker>MARKER</Marker>
<IsTruncated>false</IsTruncated>
</ListUsersResult>
<ResponseMetadata>
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
</ResponseMetadata>
</ListUsersResponse>

View File

@ -1,117 +0,0 @@
package org.jclouds.rds;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.rds.domain.Instance;
import org.jclouds.rds.domain.SecurityGroup;
import org.jclouds.rds.domain.SubnetGroup;
import org.jclouds.rds.features.InstanceApi;
import org.jclouds.rds.features.SecurityGroupApi;
import org.jclouds.rds.features.SubnetGroupApi;
import org.jclouds.rds.options.ListInstancesOptions;
import org.jclouds.rds.options.ListSecurityGroupsOptions;
import org.jclouds.rds.options.ListSubnetGroupsOptions;
import com.google.common.base.Function;
/**
* Utilities for using RDS.
*
* @author Adrian Cole
*/
public class RDS {
/**
* List instances based on the criteria in the {@link ListInstancesOptions} passed in.
*
* @param instanceApi
* the {@link InstanceApi} to use for the request
* @param options
* the {@link ListInstancesOptions} describing the ListInstances request
*
* @return iterable of instances fitting the criteria
*/
public static Iterable<Instance> listInstances(final InstanceApi instanceApi,
final ListInstancesOptions options) {
return PaginatedIterables.lazyContinue(instanceApi.list(options),
new Function<Object, PaginatedIterable<Instance>>() {
@Override
public PaginatedIterable<Instance> apply(Object input) {
return instanceApi.list(options.clone().afterMarker(input));
}
@Override
public String toString() {
return "listInstances(" + options + ")";
}
});
}
public static Iterable<Instance> listInstances(InstanceApi instanceApi) {
return listInstances(instanceApi, new ListInstancesOptions());
}
/**
* List securityGroups based on the criteria in the {@link ListSecurityGroupsOptions} passed in.
*
* @param securityGroupApi
* the {@link SecurityGroupApi} to use for the request
* @param options
* the {@link ListSecurityGroupsOptions} describing the ListSecurityGroups request
*
* @return iterable of securityGroups fitting the criteria
*/
public static Iterable<SecurityGroup> listSecurityGroups(final SecurityGroupApi securityGroupApi,
final ListSecurityGroupsOptions options) {
return PaginatedIterables.lazyContinue(securityGroupApi.list(options),
new Function<Object, PaginatedIterable<SecurityGroup>>() {
@Override
public PaginatedIterable<SecurityGroup> apply(Object input) {
return securityGroupApi.list(options.clone().afterMarker(input));
}
@Override
public String toString() {
return "listSecurityGroups(" + options + ")";
}
});
}
public static Iterable<SecurityGroup> listSecurityGroups(SecurityGroupApi securityGroupApi) {
return listSecurityGroups(securityGroupApi, new ListSecurityGroupsOptions());
}
/**
* List subnetGroups based on the criteria in the {@link ListSubnetGroupsOptions} passed in.
*
* @param subnetGroupApi
* the {@link SubnetGroupApi} to use for the request
* @param options
* the {@link ListSubnetGroupsOptions} describing the ListSubnetGroups request
*
* @return iterable of subnetGroups fitting the criteria
*/
public static Iterable<SubnetGroup> listSubnetGroups(final SubnetGroupApi subnetGroupApi,
final ListSubnetGroupsOptions options) {
return PaginatedIterables.lazyContinue(subnetGroupApi.list(options),
new Function<Object, PaginatedIterable<SubnetGroup>>() {
@Override
public PaginatedIterable<SubnetGroup> apply(Object input) {
return subnetGroupApi.list(options.clone().afterMarker(input));
}
@Override
public String toString() {
return "listSubnetGroups(" + options + ")";
}
});
}
public static Iterable<SubnetGroup> listSubnetGroups(SubnetGroupApi subnetGroupApi) {
return listSubnetGroups(subnetGroupApi, new ListSubnetGroupsOptions());
}
}

View File

@ -20,7 +20,8 @@ package org.jclouds.rds.features;
import java.util.concurrent.TimeUnit;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.concurrent.Timeout;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rds.domain.Instance;
@ -61,14 +62,14 @@ public interface InstanceApi {
*
* @return the response object
*/
PaginatedIterable<Instance> list(ListInstancesOptions options);
IterableWithMarker<Instance> list(ListInstancesOptions options);
/**
* Returns information about provisioned RDS instances.
*
* @return the response object
*/
PaginatedIterable<Instance> list();
PagedIterable<Instance> list();
/**
* Deletes the specified Instance.

View File

@ -25,14 +25,17 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.rds.domain.Instance;
import org.jclouds.rds.functions.InstancesToPagedIterable;
import org.jclouds.rds.options.ListInstancesOptions;
import org.jclouds.rds.xml.DescribeDBInstancesResultHandler;
import org.jclouds.rds.xml.InstanceHandler;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.Transform;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
@ -69,8 +72,9 @@ public interface InstanceAsyncApi {
@POST
@Path("/")
@XMLResponseParser(DescribeDBInstancesResultHandler.class)
@Transform(InstancesToPagedIterable.class)
@FormParams(keys = "Action", values = "DescribeDBInstances")
ListenableFuture<PaginatedIterable<Instance>> list();
ListenableFuture<PagedIterable<Instance>> list();
/**
* @see InstanceApi#list(ListInstancesOptions)
@ -79,7 +83,7 @@ public interface InstanceAsyncApi {
@Path("/")
@XMLResponseParser(DescribeDBInstancesResultHandler.class)
@FormParams(keys = "Action", values = "DescribeDBInstances")
ListenableFuture<PaginatedIterable<Instance>> list(ListInstancesOptions options);
ListenableFuture<IterableWithMarker<Instance>> list(ListInstancesOptions options);
/**
* @see InstanceApi#delete()

View File

@ -20,7 +20,8 @@ package org.jclouds.rds.features;
import java.util.concurrent.TimeUnit;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.concurrent.Timeout;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rds.domain.SecurityGroup;
@ -58,14 +59,14 @@ public interface SecurityGroupApi {
*
* @return the response object
*/
PaginatedIterable<SecurityGroup> list(ListSecurityGroupsOptions options);
IterableWithMarker<SecurityGroup> list(ListSecurityGroupsOptions options);
/**
* Returns a list of {@link SecurityGroup}s.
*
* @return the response object
*/
PaginatedIterable<SecurityGroup> list();
PagedIterable<SecurityGroup> list();
/**
* Deletes a DB security group.

View File

@ -25,14 +25,17 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.rds.domain.SecurityGroup;
import org.jclouds.rds.functions.SecurityGroupsToPagedIterable;
import org.jclouds.rds.options.ListSecurityGroupsOptions;
import org.jclouds.rds.xml.DescribeDBSecurityGroupsResultHandler;
import org.jclouds.rds.xml.SecurityGroupHandler;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.Transform;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
@ -69,8 +72,9 @@ public interface SecurityGroupAsyncApi {
@POST
@Path("/")
@XMLResponseParser(DescribeDBSecurityGroupsResultHandler.class)
@Transform(SecurityGroupsToPagedIterable.class)
@FormParams(keys = "Action", values = "DescribeDBSecurityGroups")
ListenableFuture<PaginatedIterable<SecurityGroup>> list();
ListenableFuture<PagedIterable<SecurityGroup>> list();
/**
* @see SecurityGroupApi#list(ListSecurityGroupsOptions)
@ -79,7 +83,7 @@ public interface SecurityGroupAsyncApi {
@Path("/")
@XMLResponseParser(DescribeDBSecurityGroupsResultHandler.class)
@FormParams(keys = "Action", values = "DescribeDBSecurityGroups")
ListenableFuture<PaginatedIterable<SecurityGroup>> list(ListSecurityGroupsOptions options);
ListenableFuture<IterableWithMarker<SecurityGroup>> list(ListSecurityGroupsOptions options);
/**
* @see SecurityGroupApi#delete()

View File

@ -20,7 +20,8 @@ package org.jclouds.rds.features;
import java.util.concurrent.TimeUnit;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.concurrent.Timeout;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rds.domain.SubnetGroup;
@ -58,14 +59,14 @@ public interface SubnetGroupApi {
*
* @return the response object
*/
PaginatedIterable<SubnetGroup> list(ListSubnetGroupsOptions options);
IterableWithMarker<SubnetGroup> list(ListSubnetGroupsOptions options);
/**
* Returns a list of {@link SubnetGroup}s.
*
* @return the response object
*/
PaginatedIterable<SubnetGroup> list();
PagedIterable<SubnetGroup> list();
/**
* Deletes a DB subnet group.

View File

@ -25,14 +25,17 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.rds.domain.SubnetGroup;
import org.jclouds.rds.functions.SubnetGroupsToPagedIterable;
import org.jclouds.rds.options.ListSubnetGroupsOptions;
import org.jclouds.rds.xml.DescribeDBSubnetGroupsResultHandler;
import org.jclouds.rds.xml.SubnetGroupHandler;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.Transform;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
@ -69,8 +72,9 @@ public interface SubnetGroupAsyncApi {
@POST
@Path("/")
@XMLResponseParser(DescribeDBSubnetGroupsResultHandler.class)
@Transform(SubnetGroupsToPagedIterable.class)
@FormParams(keys = "Action", values = "DescribeDBSubnetGroups")
ListenableFuture<PaginatedIterable<SubnetGroup>> list();
ListenableFuture<PagedIterable<SubnetGroup>> list();
/**
* @see SubnetGroupApi#list(ListSubnetGroupsOptions)
@ -79,7 +83,7 @@ public interface SubnetGroupAsyncApi {
@Path("/")
@XMLResponseParser(DescribeDBSubnetGroupsResultHandler.class)
@FormParams(keys = "Action", values = "DescribeDBSubnetGroups")
ListenableFuture<PaginatedIterable<SubnetGroup>> list(ListSubnetGroupsOptions options);
ListenableFuture<IterableWithMarker<SubnetGroup>> list(ListSubnetGroupsOptions options);
/**
* @see SubnetGroupApi#delete()

View File

@ -0,0 +1,65 @@
/**
* 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.rds.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
import org.jclouds.rds.RDSApi;
import org.jclouds.rds.domain.Instance;
import org.jclouds.rds.features.InstanceApi;
import org.jclouds.rds.options.ListInstancesOptions;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Beta
public class InstancesToPagedIterable extends CallerArg0ToPagedIterable<Instance, InstancesToPagedIterable> {
private final RDSApi api;
@Inject
protected InstancesToPagedIterable(RDSApi api) {
this.api = checkNotNull(api, "api");
}
@Override
protected Function<Object, IterableWithMarker<Instance>> markerToNextForCallingArg0(final String arg0) {
final InstanceApi instanceApi = api.getInstanceApiForRegion(arg0);
return new Function<Object, IterableWithMarker<Instance>>() {
@Override
public IterableWithMarker<Instance> apply(Object input) {
return instanceApi.list(ListInstancesOptions.Builder.afterMarker(input));
}
@Override
public String toString() {
return "listInstancesInRegion(" + arg0 + ")";
}
};
}
}

View File

@ -0,0 +1,65 @@
/**
* 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.rds.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
import org.jclouds.rds.RDSApi;
import org.jclouds.rds.domain.SecurityGroup;
import org.jclouds.rds.features.SecurityGroupApi;
import org.jclouds.rds.options.ListSecurityGroupsOptions;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Beta
public class SecurityGroupsToPagedIterable extends CallerArg0ToPagedIterable<SecurityGroup, SecurityGroupsToPagedIterable> {
private final RDSApi api;
@Inject
protected SecurityGroupsToPagedIterable(RDSApi api) {
this.api = checkNotNull(api, "api");
}
@Override
protected Function<Object, IterableWithMarker<SecurityGroup>> markerToNextForCallingArg0(final String arg0) {
final SecurityGroupApi securityGroupApi = api.getSecurityGroupApiForRegion(arg0);
return new Function<Object, IterableWithMarker<SecurityGroup>>() {
@Override
public IterableWithMarker<SecurityGroup> apply(Object input) {
return securityGroupApi.list(ListSecurityGroupsOptions.Builder.afterMarker(input));
}
@Override
public String toString() {
return "listSecurityGroupsInRegion(" + arg0 + ")";
}
};
}
}

View File

@ -0,0 +1,65 @@
/**
* 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.rds.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
import org.jclouds.rds.RDSApi;
import org.jclouds.rds.domain.SubnetGroup;
import org.jclouds.rds.features.SubnetGroupApi;
import org.jclouds.rds.options.ListSubnetGroupsOptions;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Beta
public class SubnetGroupsToPagedIterable extends CallerArg0ToPagedIterable<SubnetGroup, SubnetGroupsToPagedIterable> {
private final RDSApi api;
@Inject
protected SubnetGroupsToPagedIterable(RDSApi api) {
this.api = checkNotNull(api, "api");
}
@Override
protected Function<Object, IterableWithMarker<SubnetGroup>> markerToNextForCallingArg0(final String arg0) {
final SubnetGroupApi subnetGroupApi = api.getSubnetGroupApiForRegion(arg0);
return new Function<Object, IterableWithMarker<SubnetGroup>>() {
@Override
public IterableWithMarker<SubnetGroup> apply(Object input) {
return subnetGroupApi.list(ListSubnetGroupsOptions.Builder.afterMarker(input));
}
@Override
public String toString() {
return "listSubnetGroupsInRegion(" + arg0 + ")";
}
};
}
}

View File

@ -23,8 +23,8 @@ import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Set;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.rds.domain.Instance;
import org.xml.sax.Attributes;
@ -41,7 +41,7 @@ import com.google.inject.Inject;
* @author Adrian Cole
*/
public class DescribeDBInstancesResultHandler extends
ParseSax.HandlerForGeneratedRequestWithResult<PaginatedIterable<Instance>> {
ParseSax.HandlerForGeneratedRequestWithResult<IterableWithMarker<Instance>> {
private final InstanceHandler instanceHandler;
@ -61,8 +61,8 @@ public class DescribeDBInstancesResultHandler extends
* {@inheritDoc}
*/
@Override
public PaginatedIterable<Instance> getResult() {
return PaginatedIterables.forwardWithMarker(instances, marker);
public IterableWithMarker<Instance> getResult() {
return IterableWithMarkers.from(instances, marker);
}
/**

View File

@ -21,8 +21,8 @@ package org.jclouds.rds.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.rds.domain.SecurityGroup;
import org.xml.sax.Attributes;
@ -40,7 +40,7 @@ import com.google.inject.Inject;
* @author Adrian Cole
*/
public class DescribeDBSecurityGroupsResultHandler extends
ParseSax.HandlerForGeneratedRequestWithResult<PaginatedIterable<SecurityGroup>> {
ParseSax.HandlerForGeneratedRequestWithResult<IterableWithMarker<SecurityGroup>> {
private final SecurityGroupHandler securityGroupHander;
@ -58,8 +58,8 @@ public class DescribeDBSecurityGroupsResultHandler extends
* {@inheritDoc}
*/
@Override
public PaginatedIterable<SecurityGroup> getResult() {
return PaginatedIterables.forwardWithMarker(securityGroups.build(), marker);
public IterableWithMarker<SecurityGroup> getResult() {
return IterableWithMarkers.from(securityGroups.build(), marker);
}
/**

View File

@ -21,8 +21,8 @@ package org.jclouds.rds.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.rds.domain.SubnetGroup;
import org.xml.sax.Attributes;
@ -40,7 +40,7 @@ import com.google.inject.Inject;
* @author Adrian Cole
*/
public class DescribeDBSubnetGroupsResultHandler extends
ParseSax.HandlerForGeneratedRequestWithResult<PaginatedIterable<SubnetGroup>> {
ParseSax.HandlerForGeneratedRequestWithResult<IterableWithMarker<SubnetGroup>> {
private final SubnetGroupHandler subnetGroupHander;
@ -58,8 +58,8 @@ public class DescribeDBSubnetGroupsResultHandler extends
* {@inheritDoc}
*/
@Override
public PaginatedIterable<SubnetGroup> getResult() {
return PaginatedIterables.forwardWithMarker(subnetGroups.build(), marker);
public IterableWithMarker<SubnetGroup> getResult() {
return IterableWithMarkers.from(subnetGroups.build(), marker);
}
/**

View File

@ -1,124 +0,0 @@
package org.jclouds.rds;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import org.easymock.EasyMock;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.rds.domain.Instance;
import org.jclouds.rds.domain.SecurityGroup;
import org.jclouds.rds.domain.SubnetGroup;
import org.jclouds.rds.features.InstanceApi;
import org.jclouds.rds.features.SecurityGroupApi;
import org.jclouds.rds.features.SubnetGroupApi;
import org.jclouds.rds.options.ListInstancesOptions;
import org.jclouds.rds.options.ListSecurityGroupsOptions;
import org.jclouds.rds.options.ListSubnetGroupsOptions;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* Tests behavior of {@code RDS}.
*
* @author Adrian Cole
*/
@Test(testName = "RDSTest")
public class RDSTest {
@Test
public void testSinglePageResultInstance() throws Exception {
InstanceApi instanceApi = createMock(InstanceApi.class);
ListInstancesOptions options = new ListInstancesOptions();
PaginatedIterable<Instance> response = PaginatedIterables.forward(ImmutableSet.of(createMock(Instance.class)));
expect(instanceApi.list(options)).andReturn(response).once();
EasyMock.replay(instanceApi);
Assert.assertEquals(1, Iterables.size(RDS.listInstances(instanceApi, options)));
}
@Test
public void testMultiPageResultInstance() throws Exception {
InstanceApi instanceApi = createMock(InstanceApi.class);
ListInstancesOptions options = new ListInstancesOptions();
PaginatedIterable<Instance> response1 = PaginatedIterables.forwardWithMarker(
ImmutableSet.of(createMock(Instance.class)), "NEXTTOKEN");
PaginatedIterable<Instance> response2 = PaginatedIterables.forward(ImmutableSet.of(createMock(Instance.class)));
expect(instanceApi.list(anyObject(ListInstancesOptions.class))).andReturn(response1).once();
expect(instanceApi.list(anyObject(ListInstancesOptions.class))).andReturn(response2).once();
EasyMock.replay(instanceApi);
Assert.assertEquals(2, Iterables.size(RDS.listInstances(instanceApi, options)));
}
@Test
public void testSinglePageResultSubnetGroup() throws Exception {
SubnetGroupApi subnetGroupApi = createMock(SubnetGroupApi.class);
ListSubnetGroupsOptions options = new ListSubnetGroupsOptions();
PaginatedIterable<SubnetGroup> response = PaginatedIterables.forward(ImmutableSet
.of(createMock(SubnetGroup.class)));
expect(subnetGroupApi.list(options)).andReturn(response).once();
EasyMock.replay(subnetGroupApi);
Assert.assertEquals(1, Iterables.size(RDS.listSubnetGroups(subnetGroupApi, options)));
}
@Test
public void testMultiPageResultSubnetGroup() throws Exception {
SubnetGroupApi subnetGroupApi = createMock(SubnetGroupApi.class);
ListSubnetGroupsOptions options = new ListSubnetGroupsOptions();
PaginatedIterable<SubnetGroup> response1 = PaginatedIterables.forwardWithMarker(
ImmutableSet.of(createMock(SubnetGroup.class)), "NEXTTOKEN");
PaginatedIterable<SubnetGroup> response2 = PaginatedIterables.forward(ImmutableSet
.of(createMock(SubnetGroup.class)));
expect(subnetGroupApi.list(anyObject(ListSubnetGroupsOptions.class))).andReturn(response1).once();
expect(subnetGroupApi.list(anyObject(ListSubnetGroupsOptions.class))).andReturn(response2).once();
EasyMock.replay(subnetGroupApi);
Assert.assertEquals(2, Iterables.size(RDS.listSubnetGroups(subnetGroupApi, options)));
}
@Test
public void testSinglePageResultSecurityGroup() throws Exception {
SecurityGroupApi securityGroupApi = createMock(SecurityGroupApi.class);
ListSecurityGroupsOptions options = new ListSecurityGroupsOptions();
PaginatedIterable<SecurityGroup> response = PaginatedIterables.forward(ImmutableSet
.of(createMock(SecurityGroup.class)));
expect(securityGroupApi.list(options)).andReturn(response).once();
EasyMock.replay(securityGroupApi);
Assert.assertEquals(1, Iterables.size(RDS.listSecurityGroups(securityGroupApi, options)));
}
@Test
public void testMultiPageResultSecurityGroup() throws Exception {
SecurityGroupApi securityGroupApi = createMock(SecurityGroupApi.class);
ListSecurityGroupsOptions options = new ListSecurityGroupsOptions();
PaginatedIterable<SecurityGroup> response1 = PaginatedIterables.forwardWithMarker(
ImmutableSet.of(createMock(SecurityGroup.class)), "NEXTTOKEN");
PaginatedIterable<SecurityGroup> response2 = PaginatedIterables.forward(ImmutableSet
.of(createMock(SecurityGroup.class)));
expect(securityGroupApi.list(anyObject(ListSecurityGroupsOptions.class))).andReturn(response1).once();
expect(securityGroupApi.list(anyObject(ListSecurityGroupsOptions.class))).andReturn(response2).once();
EasyMock.replay(securityGroupApi);
Assert.assertEquals(2, Iterables.size(RDS.listSecurityGroups(securityGroupApi, options)));
}
}

View File

@ -33,6 +33,9 @@ import org.jclouds.rds.parse.GetInstanceResponseTest;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@ -44,21 +47,21 @@ public class InstanceApiExpectTest extends BaseRDSApiExpectTest {
}
HttpRequest get = HttpRequest.builder()
.method("POST")
.endpoint("https://rds.us-east-1.amazonaws.com/")
.addHeader("Host", "rds.us-east-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=DescribeDBInstances" +
"&DBInstanceIdentifier=id" +
"&Signature=jcvzapwazR2OuWnMILEt48ycu226NOn2AuEBKSxV2O0%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2012-04-23" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
.method("POST")
.endpoint("https://rds.us-east-1.amazonaws.com/")
.addHeader("Host", "rds.us-east-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=DescribeDBInstances" +
"&DBInstanceIdentifier=id" +
"&Signature=jcvzapwazR2OuWnMILEt48ycu226NOn2AuEBKSxV2O0%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2012-04-23" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
public void testGetWhenResponseIs2xx() throws Exception {
@ -83,20 +86,20 @@ public class InstanceApiExpectTest extends BaseRDSApiExpectTest {
}
HttpRequest list = HttpRequest.builder()
.method("POST")
.endpoint("https://rds.us-east-1.amazonaws.com/")
.addHeader("Host", "rds.us-east-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=DescribeDBInstances" +
"&Signature=SnClCujZG9Sq9sMdf59xZWsjQxIbMOp5YEF%2FFBsurf4%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2012-04-23" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
.method("POST")
.endpoint("https://rds.us-east-1.amazonaws.com/")
.addHeader("Host", "rds.us-east-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=DescribeDBInstances" +
"&Signature=SnClCujZG9Sq9sMdf59xZWsjQxIbMOp5YEF%2FFBsurf4%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2012-04-23" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
public void testListWhenResponseIs2xx() throws Exception {
@ -106,9 +109,42 @@ public class InstanceApiExpectTest extends BaseRDSApiExpectTest {
RDSApi apiWhenExist = requestSendsResponse(
list, listResponse);
assertEquals(apiWhenExist.getInstanceApi().list().toString(), new DescribeDBInstancesResponseTest().expected().toString());
assertEquals(apiWhenExist.getInstanceApi().list().get(0).toString(), new DescribeDBInstancesResponseTest().expected().toString());
}
public void testList2PagesWhenResponseIs2xx() throws Exception {
HttpResponse listResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/describe_instances_marker.xml", "text/xml")).build();
HttpRequest list2 = HttpRequest.builder()
.method("POST")
.endpoint("https://rds.us-east-1.amazonaws.com/")
.addHeader("Host", "rds.us-east-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=DescribeDBInstances" +
"&Marker=MARKER" +
"&Signature=TFW8vaU2IppmBey0ZHttbWz4rMFh%2F5ACWl6Xyt58sQU%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2012-04-23" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
HttpResponse list2Response = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/describe_instances.xml", "text/xml")).build();
RDSApi apiWhenExist = requestsSendResponses(
list, listResponse, list2, list2Response);
assertEquals(ImmutableList.copyOf(Iterables.concat(apiWhenExist.getInstanceApi().list())),
ImmutableList.copyOf(Iterables.concat(new DescribeDBInstancesResponseTest().expected(),
new DescribeDBInstancesResponseTest().expected())));
}
// TODO: this should really be an empty set
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testListWhenResponseIs404() throws Exception {
@ -118,7 +154,7 @@ public class InstanceApiExpectTest extends BaseRDSApiExpectTest {
RDSApi apiWhenDontExist = requestSendsResponse(
list, listResponse);
apiWhenDontExist.getInstanceApi().list();
apiWhenDontExist.getInstanceApi().list().get(0);
}
public void testListWithOptionsWhenResponseIs2xx() throws Exception {

View File

@ -20,7 +20,7 @@ package org.jclouds.rds.features;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.rds.domain.Instance;
import org.jclouds.rds.internal.BaseRDSApiLiveTest;
import org.jclouds.rds.options.ListInstancesOptions;
@ -49,7 +49,7 @@ public class InstanceApiLiveTest extends BaseRDSApiLiveTest {
@Test
protected void testDescribeInstances() {
PaginatedIterable<Instance> response = api().list();
IterableWithMarker<Instance> response = api().list().get(0);
for (Instance instance : response) {
checkInstance(instance);
@ -61,7 +61,7 @@ public class InstanceApiLiveTest extends BaseRDSApiLiveTest {
}
// Test with a Marker, even if it's null
response = api().list(ListInstancesOptions.Builder.afterMarker(response.getNextMarker()));
response = api().list(ListInstancesOptions.Builder.afterMarker(response.nextMarker().orNull()));
for (Instance instance : response) {
checkInstance(instance);
}

View File

@ -33,6 +33,9 @@ import org.jclouds.rds.parse.GetSecurityGroupResponseTest;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@ -106,9 +109,42 @@ public class SecurityGroupApiExpectTest extends BaseRDSApiExpectTest {
RDSApi apiWhenExist = requestSendsResponse(
list, listResponse);
assertEquals(apiWhenExist.getSecurityGroupApi().list().toString(), new DescribeDBSecurityGroupsResponseTest().expected().toString());
assertEquals(apiWhenExist.getSecurityGroupApi().list().get(0).toString(), new DescribeDBSecurityGroupsResponseTest().expected().toString());
}
public void testList2PagesWhenResponseIs2xx() throws Exception {
HttpResponse listResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/describe_securitygroups_marker.xml", "text/xml")).build();
HttpRequest list2 = HttpRequest.builder()
.method("POST")
.endpoint("https://rds.us-east-1.amazonaws.com/")
.addHeader("Host", "rds.us-east-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=DescribeDBSecurityGroups" +
"&Marker=MARKER" +
"&Signature=DeZcA5ViQu%2FbB3PY9EmRZavRgYxLFMvdbq7topMKKhw%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2012-04-23" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
HttpResponse list2Response = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/describe_securitygroups.xml", "text/xml")).build();
RDSApi apiWhenExist = requestsSendResponses(
list, listResponse, list2, list2Response);
assertEquals(ImmutableList.copyOf(Iterables.concat(apiWhenExist.getSecurityGroupApi().list())),
ImmutableList.copyOf(Iterables.concat(new DescribeDBSecurityGroupsResponseTest().expected(),
new DescribeDBSecurityGroupsResponseTest().expected())));
}
// TODO: this should really be an empty set
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testListWhenResponseIs404() throws Exception {
@ -118,7 +154,7 @@ public class SecurityGroupApiExpectTest extends BaseRDSApiExpectTest {
RDSApi apiWhenDontExist = requestSendsResponse(
list, listResponse);
apiWhenDontExist.getSecurityGroupApi().list();
apiWhenDontExist.getSecurityGroupApi().list().get(0);
}
public void testListWithOptionsWhenResponseIs2xx() throws Exception {

View File

@ -20,7 +20,7 @@ package org.jclouds.rds.features;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.rds.domain.EC2SecurityGroup;
import org.jclouds.rds.domain.SecurityGroup;
import org.jclouds.rds.internal.BaseRDSApiLiveTest;
@ -55,7 +55,7 @@ public class SecurityGroupApiLiveTest extends BaseRDSApiLiveTest {
@Test
protected void testDescribeSecurityGroups() {
PaginatedIterable<SecurityGroup> response = api().list();
IterableWithMarker<SecurityGroup> response = api().list().get(0);
for (SecurityGroup securityGroup : response) {
checkSecurityGroup(securityGroup);
@ -67,7 +67,7 @@ public class SecurityGroupApiLiveTest extends BaseRDSApiLiveTest {
}
// Test with a Marker, even if it's null
response = api().list(ListSecurityGroupsOptions.Builder.afterMarker(response.getNextMarker()));
response = api().list(ListSecurityGroupsOptions.Builder.afterMarker(response.nextMarker().orNull()));
for (SecurityGroup securityGroup : response) {
checkSecurityGroup(securityGroup);
}

View File

@ -33,6 +33,9 @@ import org.jclouds.rds.parse.GetSubnetGroupResponseTest;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@ -106,9 +109,43 @@ public class SubnetGroupApiExpectTest extends BaseRDSApiExpectTest {
RDSApi apiWhenExist = requestSendsResponse(
list, listResponse);
assertEquals(apiWhenExist.getSubnetGroupApi().list().toString(), new DescribeDBSubnetGroupsResponseTest().expected().toString());
assertEquals(apiWhenExist.getSubnetGroupApi().list().get(0).toString(), new DescribeDBSubnetGroupsResponseTest().expected().toString());
}
public void testList2PagesWhenResponseIs2xx() throws Exception {
HttpResponse listResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/describe_subnetgroups_marker.xml", "text/xml")).build();
HttpRequest list2 = HttpRequest.builder()
.method("POST")
.endpoint("https://rds.us-east-1.amazonaws.com/")
.addHeader("Host", "rds.us-east-1.amazonaws.com")
.payload(
payloadFromStringWithContentType(
"Action=DescribeDBSubnetGroups" +
"&Marker=MARKER" +
"&Signature=1yK3VgSfUKDNHEwicyYbnMvSPAeJ7DZvi52gQeUUFSQ%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2012-04-23" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
HttpResponse list2Response = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/describe_subnetgroups.xml", "text/xml")).build();
RDSApi apiWhenExist = requestsSendResponses(
list, listResponse, list2, list2Response);
assertEquals(ImmutableList.copyOf(Iterables.concat(apiWhenExist.getSubnetGroupApi().list())),
ImmutableList.copyOf(Iterables.concat(new DescribeDBSubnetGroupsResponseTest().expected(),
new DescribeDBSubnetGroupsResponseTest().expected())));
}
// TODO: this should really be an empty set
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testListWhenResponseIs404() throws Exception {
@ -118,7 +155,7 @@ public class SubnetGroupApiExpectTest extends BaseRDSApiExpectTest {
RDSApi apiWhenDontExist = requestSendsResponse(
list, listResponse);
apiWhenDontExist.getSubnetGroupApi().list();
apiWhenDontExist.getSubnetGroupApi().list().get(0);
}
public void testListWithOptionsWhenResponseIs2xx() throws Exception {

View File

@ -21,7 +21,7 @@ package org.jclouds.rds.features;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.rds.domain.Subnet;
import org.jclouds.rds.domain.SubnetGroup;
import org.jclouds.rds.internal.BaseRDSApiLiveTest;
@ -55,7 +55,7 @@ public class SubnetGroupApiLiveTest extends BaseRDSApiLiveTest {
@Test
protected void testDescribeSubnetGroups() {
PaginatedIterable<SubnetGroup> response = api().list();
IterableWithMarker<SubnetGroup> response = api().list().get(0);
for (SubnetGroup subnetGroup : response) {
checkSubnetGroup(subnetGroup);
@ -67,7 +67,7 @@ public class SubnetGroupApiLiveTest extends BaseRDSApiLiveTest {
}
// Test with a Marker, even if it's null
response = api().list(ListSubnetGroupsOptions.Builder.afterMarker(response.getNextMarker()));
response = api().list(ListSubnetGroupsOptions.Builder.afterMarker(response.nextMarker().orNull()));
for (SubnetGroup subnetGroup : response) {
checkSubnetGroup(subnetGroup);
}

View File

@ -22,8 +22,8 @@ import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.functions.BaseHandlerTest;
@ -45,17 +45,17 @@ public class DescribeDBInstancesResponseTest extends BaseHandlerTest {
public void test() {
InputStream is = getClass().getResourceAsStream("/describe_instances.xml");
PaginatedIterable<Instance> expected = expected();
IterableWithMarker<Instance> expected = expected();
DescribeDBInstancesResultHandler handler = injector.getInstance(DescribeDBInstancesResultHandler.class);
PaginatedIterable<Instance> result = factory.create(handler).parse(is);
IterableWithMarker<Instance> result = factory.create(handler).parse(is);
assertEquals(result.toString(), expected.toString());
}
public PaginatedIterable<Instance> expected() {
return PaginatedIterables.forward(ImmutableSet.<Instance>builder()
public IterableWithMarker<Instance> expected() {
return IterableWithMarkers.from(ImmutableSet.<Instance>builder()
.add(Instance.builder()
.engine("mysql")
.multiAZ(false)

View File

@ -22,8 +22,8 @@ import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.rds.domain.EC2SecurityGroup;
import org.jclouds.rds.domain.IPRange;
@ -43,17 +43,17 @@ public class DescribeDBSecurityGroupsResponseTest extends BaseHandlerTest {
public void test() {
InputStream is = getClass().getResourceAsStream("/describe_securitygroups.xml");
PaginatedIterable<SecurityGroup> expected = expected();
IterableWithMarker<SecurityGroup> expected = expected();
DescribeDBSecurityGroupsResultHandler handler = injector.getInstance(DescribeDBSecurityGroupsResultHandler.class);
PaginatedIterable<SecurityGroup> result = factory.create(handler).parse(is);
IterableWithMarker<SecurityGroup> result = factory.create(handler).parse(is);
assertEquals(result.toString(), expected.toString());
}
public PaginatedIterable<SecurityGroup> expected() {
return PaginatedIterables.forward(ImmutableSet.<SecurityGroup>builder()
public IterableWithMarker<SecurityGroup> expected() {
return IterableWithMarkers.from(ImmutableSet.<SecurityGroup>builder()
.add(SecurityGroup.builder()
.ec2SecurityGroup(EC2SecurityGroup.builder()
.status("authorized")

View File

@ -22,8 +22,8 @@ import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.collect.PaginatedIterable;
import org.jclouds.collect.PaginatedIterables;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.rds.domain.Subnet;
import org.jclouds.rds.domain.SubnetGroup;
@ -42,17 +42,17 @@ public class DescribeDBSubnetGroupsResponseTest extends BaseHandlerTest {
public void test() {
InputStream is = getClass().getResourceAsStream("/describe_subnetgroups.xml");
PaginatedIterable<SubnetGroup> expected = expected();
IterableWithMarker<SubnetGroup> expected = expected();
DescribeDBSubnetGroupsResultHandler handler = injector.getInstance(DescribeDBSubnetGroupsResultHandler.class);
PaginatedIterable<SubnetGroup> result = factory.create(handler).parse(is);
IterableWithMarker<SubnetGroup> result = factory.create(handler).parse(is);
assertEquals(result.toString(), expected.toString());
}
public PaginatedIterable<SubnetGroup> expected() {
return PaginatedIterables.forward(ImmutableSet.<SubnetGroup>builder()
public IterableWithMarker<SubnetGroup> expected() {
return IterableWithMarkers.from(ImmutableSet.<SubnetGroup>builder()
.add(SubnetGroup.builder()
.vpcId("990524496922")
.status("Complete")

View File

@ -0,0 +1,46 @@
<DescribeDBInstancesResponse xmlns="http://rds.amazonaws.com/doc/2012-04-23/">
<DescribeDBInstancesResult>
<DBInstances>
<DBInstance>
<ReadReplicaDBInstanceIdentifiers/>
<LatestRestorableTime>2011-05-23T06:50:00Z</LatestRestorableTime>
<Engine>mysql</Engine>
<PendingModifiedValues/>
<BackupRetentionPeriod>1</BackupRetentionPeriod>
<MultiAZ>false</MultiAZ>
<LicenseModel>general-public-license</LicenseModel>
<DBInstanceStatus>available</DBInstanceStatus>
<EngineVersion>5.1.50</EngineVersion>
<Endpoint>
<Port>3306</Port>
<Address>simcoprod01.cu7u2t4uz396.us-east-1.rds.amazonaws.com</Address>
</Endpoint>
<DBInstanceIdentifier>simcoprod01</DBInstanceIdentifier>
<DBParameterGroups>
<DBParameterGroup>
<ParameterApplyStatus>in-sync</ParameterApplyStatus>
<DBParameterGroupName>default.mysql5.1</DBParameterGroupName>
</DBParameterGroup>
</DBParameterGroups>
<DBSecurityGroups>
<DBSecurityGroup>
<Status>active</Status>
<DBSecurityGroupName>default</DBSecurityGroupName>
</DBSecurityGroup>
</DBSecurityGroups>
<PreferredBackupWindow>00:00-00:30</PreferredBackupWindow>
<AutoMinorVersionUpgrade>true</AutoMinorVersionUpgrade>
<PreferredMaintenanceWindow>sat:07:30-sat:08:00</PreferredMaintenanceWindow>
<AvailabilityZone>us-east-1a</AvailabilityZone>
<InstanceCreateTime>2011-05-23T06:06:43.110Z</InstanceCreateTime>
<AllocatedStorage>10</AllocatedStorage>
<DBInstanceClass>db.m1.large</DBInstanceClass>
<MasterUsername>master</MasterUsername>
</DBInstance>
</DBInstances>
<Marker>MARKER</Marker>
</DescribeDBInstancesResult>
<ResponseMetadata>
<RequestId>9135fff3-8509-11e0-bd9b-a7b1ece36d51</RequestId>
</ResponseMetadata>
</DescribeDBInstancesResponse>

View File

@ -0,0 +1,50 @@
<DescribeDBSecurityGroupsResponse xmlns="http://rds.amazonaws.com/doc/2012-04-23/">
<DescribeDBSecurityGroupsResult>
<DBSecurityGroups>
<DBSecurityGroup>
<EC2SecurityGroups>
<EC2SecurityGroup>
<Status>authorized</Status>
<EC2SecurityGroupName>myec2securitygroup</EC2SecurityGroupName>
<EC2SecurityGroupOwnerId>054794666394</EC2SecurityGroupOwnerId>
</EC2SecurityGroup>
</EC2SecurityGroups>
<DBSecurityGroupDescription>default</DBSecurityGroupDescription>
<IPRanges>
<IPRange>
<CIDRIP>127.0.0.1/30</CIDRIP>
<Status>authorized</Status>
</IPRange>
</IPRanges>
<OwnerId>621567473609</OwnerId>
<DBSecurityGroupName>default</DBSecurityGroupName>
<VpcId>vpc-1ab2c3d4</VpcId>
</DBSecurityGroup>
<DBSecurityGroup>
<EC2SecurityGroups/>
<DBSecurityGroupDescription>My new DBSecurityGroup</DBSecurityGroupDescription>
<IPRanges>
<IPRange>
<CIDRIP>192.168.1.1/24</CIDRIP>
<Status>authorized</Status>
</IPRange>
</IPRanges>
<OwnerId>621567473609</OwnerId>
<DBSecurityGroupName>mydbsecuritygroup</DBSecurityGroupName>
<VpcId>vpc-1ab2c3d5</VpcId>
</DBSecurityGroup>
<DBSecurityGroup>
<EC2SecurityGroups/>
<DBSecurityGroupDescription>My new DBSecurityGroup</DBSecurityGroupDescription>
<IPRanges/>
<OwnerId>621567473609</OwnerId>
<DBSecurityGroupName>mydbsecuritygroup4</DBSecurityGroupName>
<VpcId>vpc-1ab2c3d6</VpcId>
</DBSecurityGroup>
</DBSecurityGroups>
<Marker>MARKER</Marker>
</DescribeDBSecurityGroupsResult>
<ResponseMetadata>
<RequestId>bbdad154-bf42-11de-86a4-97241dfaadff</RequestId>
</ResponseMetadata>
</DescribeDBSecurityGroupsResponse>

View File

@ -0,0 +1,71 @@
<DescribeDBSubnetGroupsResponse
xmlns="http://rds.amazonaws.com/doc/2012-04-23/">
<DescribeDBSubnetGroupsResult>
<DBSubnetGroups>
<DBSubnetGroup>
<VpcId>990524496922</VpcId>
<SubnetGroupStatus>Complete</SubnetGroupStatus>
<DBSubnetGroupDescription>description
</DBSubnetGroupDescription>
<DBSubnetGroupName>subnet_grp1</DBSubnetGroupName>
<Subnets>
<Subnet>
<SubnetStatus>Active</SubnetStatus>
<SubnetIdentifier>subnet-7c5b4115</SubnetIdentifier>
<SubnetAvailabilityZone>
<Name>us-east-1c</Name>
</SubnetAvailabilityZone>
</Subnet>
<Subnet>
<SubnetStatus>Active</SubnetStatus>
<SubnetIdentifier>subnet-7b5b4112</SubnetIdentifier>
<SubnetAvailabilityZone>
<Name>us-east-1b</Name>
</SubnetAvailabilityZone>
</Subnet>
<Subnet>
<SubnetStatus>Active</SubnetStatus>
<SubnetIdentifier>subnet-3ea6bd57</SubnetIdentifier>
<SubnetAvailabilityZone>
<Name>us-east-1d</Name>
</SubnetAvailabilityZone>
</Subnet>
</Subnets>
</DBSubnetGroup>
<DBSubnetGroup>
<VpcId>990524496922</VpcId>
<SubnetGroupStatus>Complete</SubnetGroupStatus>
<DBSubnetGroupDescription>description
</DBSubnetGroupDescription>
<DBSubnetGroupName>subnet_grp2</DBSubnetGroupName>
<Subnets>
<Subnet>
<SubnetStatus>Active</SubnetStatus>
<SubnetIdentifier>subnet-7c5b4115</SubnetIdentifier>
<SubnetAvailabilityZone>
<Name>us-east-1c</Name>
</SubnetAvailabilityZone>
</Subnet>
<Subnet>
<SubnetStatus>Active</SubnetStatus>
<SubnetIdentifier>subnet-7b5b4112</SubnetIdentifier>
<SubnetAvailabilityZone>
<Name>us-east-1b</Name>
</SubnetAvailabilityZone>
</Subnet>
<Subnet>
<SubnetStatus>Active</SubnetStatus>
<SubnetIdentifier>subnet-3ea6bd57</SubnetIdentifier>
<SubnetAvailabilityZone>
<Name>us-east-1d</Name>
</SubnetAvailabilityZone>
</Subnet>
</Subnets>
</DBSubnetGroup>
</DBSubnetGroups>
<Marker>MARKER</Marker>
</DescribeDBSubnetGroupsResult>
<ResponseMetadata>
<RequestId>31d0faee-229b-11e1-81f1-df3a2a803dad</RequestId>
</ResponseMetadata>
</DescribeDBSubnetGroupsResponse>

View File

@ -0,0 +1,33 @@
/**
* 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.aws.cloudwatch.features;
import org.jclouds.cloudwatch.features.MetricApiLiveTest;
import org.testng.annotations.Test;
/**
* @author Jeremy Whitlock, Adrian Cole
*/
@Test(groups = "live", testName = "AWSMetricApiLiveTest")
public class AWSMetricApiLiveTest extends MetricApiLiveTest {
public AWSMetricApiLiveTest(){
provider = "aws-cloudwatch";
}
}