From 410b94716004238197985cf3a96077b45929657a Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Thu, 6 Oct 2011 23:42:15 +0100 Subject: [PATCH] 612: Change Multimap occurences to Maps with Iterable values --- .../java/org/jclouds/aws/util/AWSUtils.java | 24 ++++- .../BindTagFiltersToIndexedFormParams.java | 8 +- .../aws/ec2/services/TagAsyncClient.java | 7 +- .../jclouds/aws/ec2/services/TagClient.java | 10 +- .../org/jclouds/aws/ec2/util/TagFilters.java | 96 ++++++++++++------- ...BindTagFiltersToIndexedFormParamsTest.java | 21 ++-- .../aws/ec2/services/TagAsyncClientTest.java | 12 +-- .../aws/ec2/services/TagClientLiveTest.java | 10 +- 8 files changed, 114 insertions(+), 74 deletions(-) diff --git a/common/aws/src/main/java/org/jclouds/aws/util/AWSUtils.java b/common/aws/src/main/java/org/jclouds/aws/util/AWSUtils.java index f8c5201026..bb72785ad3 100644 --- a/common/aws/src/main/java/org/jclouds/aws/util/AWSUtils.java +++ b/common/aws/src/main/java/org/jclouds/aws/util/AWSUtils.java @@ -47,6 +47,7 @@ import org.jclouds.rest.internal.GeneratedHttpRequest; import com.google.common.base.Function; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap.Builder; +import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; /** @@ -142,7 +143,7 @@ public class AWSUtils { checkArgument(checkNotNull(input, "input") instanceof String[], "this binder is only valid for String[] : " + input.getClass()); String[] values = (String[]) input; - Builder builder = ImmutableMultimap.builder(); + Builder builder = ImmutableMultimap. builder(); for (int i = 0; i < values.length; i++) { builder.put(prefix + "." + (i + 1), checkNotNull(values[i], prefix.toLowerCase() + "s[" + i + "]")); } @@ -174,7 +175,26 @@ public class AWSUtils { int i = 1; for (Object k : map.keySet()) { builder.put(prefix + "." + i + "." + keySuffix, checkNotNull(k.toString(), keySuffix.toLowerCase() + "s[" + i + "]")); - if (!map.get(k).isEmpty()) { + int j = 1; + for (Object v : map.get(k)) { + builder.put(prefix + "." + i + "." + valueSuffix + "." + j, v.toString()); + j++; + } + i++; + } + ImmutableMultimap forms = builder.build(); + return forms.size() == 0 ? request : ModifyRequest.putFormParams(request, forms); + } + + @SuppressWarnings("unchecked") + public static R indexMapOfIterableToFormValuesWithPrefix(R request, String prefix, String keySuffix, String valueSuffix, Object input) { + checkArgument(checkNotNull(input, "input") instanceof Map, "this binder is only valid for Map>: " + input.getClass()); + Map> map = (Map>) input; + Builder builder = ImmutableMultimap. builder(); + int i = 1; + for (Object k : map.keySet()) { + builder.put(prefix + "." + i + "." + keySuffix, checkNotNull(k.toString(), keySuffix.toLowerCase() + "s[" + i + "]")); + if (!Iterables.isEmpty(map.get(k))) { int j = 1; for (Object v : map.get(k)) { builder.put(prefix + "." + i + "." + valueSuffix + "." + j, v.toString()); diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindTagFiltersToIndexedFormParams.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindTagFiltersToIndexedFormParams.java index 1058734569..55d0d85e64 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindTagFiltersToIndexedFormParams.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindTagFiltersToIndexedFormParams.java @@ -20,19 +20,19 @@ package org.jclouds.aws.ec2.binders; import static com.google.common.base.Preconditions.*; +import java.util.Map; + import org.jclouds.aws.util.AWSUtils; import org.jclouds.http.HttpRequest; import org.jclouds.rest.Binder; -import com.google.common.collect.Multimap; - /** * @author grkvlt@apache.org */ public class BindTagFiltersToIndexedFormParams implements Binder { @Override public R bindToRequest(R request, Object input) { - checkArgument(checkNotNull(input, "input") instanceof Multimap, "this binder is only valid for Multimap"); - return AWSUtils.indexMultimapToFormValuesWithPrefix(request, "Filter", "Name", "Value", input); + checkArgument(checkNotNull(input, "input") instanceof Map, "this binder is only valid for Map>"); + return AWSUtils.indexMapOfIterableToFormValuesWithPrefix(request, "Filter", "Name", "Value", input); } } diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/TagAsyncClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/TagAsyncClient.java index 5b1ffd36c9..bba53f1ff7 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/TagAsyncClient.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/TagAsyncClient.java @@ -31,7 +31,7 @@ import org.jclouds.aws.ec2.binders.BindResourceIdsToIndexedFormParams; import org.jclouds.aws.ec2.binders.BindTagFiltersToIndexedFormParams; import org.jclouds.aws.ec2.binders.BindTagsToIndexedFormParams; import org.jclouds.aws.ec2.domain.Tag; -import org.jclouds.aws.ec2.util.TagFilters; +import org.jclouds.aws.ec2.util.TagFilters.FilterName; import org.jclouds.aws.ec2.xml.DescribeTagsResponseHandler; import org.jclouds.aws.filters.FormSigner; import org.jclouds.javax.annotation.Nullable; @@ -46,7 +46,6 @@ import org.jclouds.rest.annotations.XMLResponseParser; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; -import com.google.common.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; /** @@ -80,7 +79,7 @@ public interface TagAsyncClient { @BinderParam(BindTagsToIndexedFormParams.class) Map tags); /** - * @see TagClient#describeTagsInRegion(String, Multimap) + * @see TagClient#describeTagsInRegion(String, Map) */ @POST @Path("/") @@ -88,5 +87,5 @@ public interface TagAsyncClient { @XMLResponseParser(DescribeTagsResponseHandler.class) @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) ListenableFuture> describeTagsInRegion(@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, - @BinderParam(BindTagFiltersToIndexedFormParams.class) Multimap filters); + @BinderParam(BindTagFiltersToIndexedFormParams.class) Map> filters); } diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/TagClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/TagClient.java index 8bf144f373..b77ff78897 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/TagClient.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/TagClient.java @@ -23,12 +23,10 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import org.jclouds.aws.ec2.domain.Tag; -import org.jclouds.aws.ec2.util.TagFilters; +import org.jclouds.aws.ec2.util.TagFilters.FilterName; import org.jclouds.concurrent.Timeout; import org.jclouds.javax.annotation.Nullable; -import com.google.common.collect.Multimap; - /** * Provides Tag services for EC2. For more information, refer to the Amazon EC2 * Developer Guide. @@ -46,7 +44,7 @@ public interface TagClient { * IDs of the resources to tag. * @param tags * The tags to create. - * @see #describeTagsInRegion(String, Multimap) + * @see #describeTagsInRegion(String, Map) * @see #deleteTagsInRegion(String, Iterable, Map) * * @see @@ -63,7 +61,7 @@ public interface TagClient { * @param tags * The tags to delete. * - * @see #describeTagsInRegion(String, Multimap) + * @see #describeTagsInRegion(String, Map) * @see #createTagsInRegion(String, Iterable, Map) * * @see @@ -82,5 +80,5 @@ public interface TagClient { * @see #createTagsInRegion(String, Iterable, Map) * @see */ - Set describeTagsInRegion(@Nullable String region, Multimap filters); + Set describeTagsInRegion(@Nullable String region, Map> filters); } diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/util/TagFilters.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/util/TagFilters.java index c5406b1342..8e877a0752 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/util/TagFilters.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/util/TagFilters.java @@ -20,10 +20,14 @@ package org.jclouds.aws.ec2.util; import static com.google.common.base.Preconditions.*; +import java.util.Map; + import com.google.common.base.CaseFormat; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSetMultimap; -import com.google.common.collect.Multimap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; /** * @author grkvlt@apache.org @@ -89,52 +93,52 @@ public class TagFilters { } } - protected final ImmutableSetMultimap.Builder map; + protected final Map> map; protected TagFilters() { - map = ImmutableSetMultimap.builder(); + map = Maps.>newLinkedHashMap(); } public static TagFilters filters() { return new TagFilters(); } - public Multimap build() { - return map.build(); + public Map> build() { + return ImmutableMap.copyOf(map); } public TagFilters resourceId(String resourceId) { - map.put(FilterName.RESOURCE_ID, resourceId); + put(FilterName.RESOURCE_ID, resourceId); return this; } public TagFilters key(String key) { - map.put(FilterName.KEY, key); + put(FilterName.KEY, key); return this; } public TagFilters keys(String...keys) { - map.putAll(FilterName.KEY, ImmutableSet.copyOf(keys)); + put(FilterName.KEY, ImmutableSet.copyOf(keys)); return this; } public TagFilters keys(Iterable keys) { - map.putAll(FilterName.KEY, ImmutableSet.copyOf(keys)); + putAll(FilterName.KEY, ImmutableSet.copyOf(keys)); return this; } public TagFilters value(String value) { - map.put(FilterName.VALUE, value); + put(FilterName.VALUE, value); return this; } public TagFilters values(String...values) { - map.putAll(FilterName.VALUE, ImmutableSet.copyOf(values)); + putAll(FilterName.VALUE, ImmutableSet.copyOf(values)); return this; } public TagFilters values(Iterable values) { - map.putAll(FilterName.VALUE, ImmutableSet.copyOf(values)); + putAll(FilterName.VALUE, ImmutableSet.copyOf(values)); return this; } @@ -187,99 +191,125 @@ public class TagFilters { } public TagFilters anyKey() { - return key("*"); + putAll(FilterName.KEY, ImmutableSet.of()); + return this; } public TagFilters anyValue() { - return value("*"); + putAll(FilterName.VALUE, ImmutableSet.of()); + return this; } public TagFilters anyResourceId() { - return resourceId("*"); + putAll(FilterName.RESOURCE_TYPE, ImmutableSet.of()); + return this; } public TagFilters anyResourceType() { - map.put(FilterName.RESOURCE_TYPE, "*"); + putAll(FilterName.RESOURCE_TYPE, ImmutableSet.of()); + return this; + } + + public TagFilters resourceType(ResourceType resourceType) { + put(FilterName.RESOURCE_TYPE, resourceType); return this; } public TagFilters customerGateway() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.CUSTOMER_GATEWAY); + put(FilterName.RESOURCE_TYPE, ResourceType.CUSTOMER_GATEWAY); return this; } public TagFilters dhcpOptions() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.DHCP_OPTIONS); + put(FilterName.RESOURCE_TYPE, ResourceType.DHCP_OPTIONS); return this; } public TagFilters image() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.IMAGE); + put(FilterName.RESOURCE_TYPE, ResourceType.IMAGE); return this; } public TagFilters instance() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.INSTANCE); + put(FilterName.RESOURCE_TYPE, ResourceType.INSTANCE); return this; } public TagFilters internetGateway() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.INTERNET_GATEWAY); + put(FilterName.RESOURCE_TYPE, ResourceType.INTERNET_GATEWAY); return this; } public TagFilters networkAcl() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.NETWORK_ACL); + put(FilterName.RESOURCE_TYPE, ResourceType.NETWORK_ACL); return this; } public TagFilters reservedInstance() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.RESERVED_INSTANCES); + put(FilterName.RESOURCE_TYPE, ResourceType.RESERVED_INSTANCES); return this; } public TagFilters routeTable() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.ROUTE_TABLE); + put(FilterName.RESOURCE_TYPE, ResourceType.ROUTE_TABLE); return this; } public TagFilters securityGroup() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.SECURITY_GROUP); + put(FilterName.RESOURCE_TYPE, ResourceType.SECURITY_GROUP); return this; } public TagFilters snapshot() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.SNAPSHOT); + put(FilterName.RESOURCE_TYPE, ResourceType.SNAPSHOT); return this; } public TagFilters instancesRequest() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.SPOT_INSTANCES_REQUEST); + put(FilterName.RESOURCE_TYPE, ResourceType.SPOT_INSTANCES_REQUEST); return this; } public TagFilters subnet() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.SUBNET); + put(FilterName.RESOURCE_TYPE, ResourceType.SUBNET); return this; } public TagFilters volume() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.VOLUME); + put(FilterName.RESOURCE_TYPE, ResourceType.VOLUME); return this; } public TagFilters vpc() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.VPC); + put(FilterName.RESOURCE_TYPE, ResourceType.VPC); return this; } public TagFilters vpnConnection() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.VPN_CONNECTION); + put(FilterName.RESOURCE_TYPE, ResourceType.VPN_CONNECTION); return this; } public TagFilters vpnGateway() { - map.put(FilterName.RESOURCE_TYPE, ResourceType.VPN_GATEWAY); + put(FilterName.RESOURCE_TYPE, ResourceType.VPN_GATEWAY); return this; } + + private void put(FilterName key, Object value) { + putAll(key, Sets.newHashSet(value)); + } + + private void putAll(FilterName key, Iterable values) { + if (values == null || Iterables.isEmpty(values)) { + // If we add an empty or null set of values, replace the value in the map entirely + map.put(key, ImmutableSet.of()); + } else { + // Add the values, to a new set if required + if (!map.containsKey(key)) { + map.put(key, Sets.newHashSet()); + } + Iterable entries = map.get(key); + map.put(key, Iterables.concat(entries, values)); + } + } } diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/binders/BindTagFiltersToIndexedFormParamsTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/binders/BindTagFiltersToIndexedFormParamsTest.java index c9944007ad..c8e7b4e7a0 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/binders/BindTagFiltersToIndexedFormParamsTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/binders/BindTagFiltersToIndexedFormParamsTest.java @@ -31,7 +31,8 @@ import org.jclouds.aws.ec2.util.TagFilters.ResourceType; import org.jclouds.http.HttpRequest; import org.testng.annotations.Test; -import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.inject.Guice; import com.google.inject.Injector; @@ -45,31 +46,31 @@ public class BindTagFiltersToIndexedFormParamsTest { Injector injector = Guice.createInjector(); BindTagFiltersToIndexedFormParams binder = injector.getInstance(BindTagFiltersToIndexedFormParams.class); - public void testResourceTypeWithValues() { + public void testMultipleResourceTypes() { HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build(); - request = binder.bindToRequest(request, ImmutableSetMultimap.builder().put(FilterName.RESOURCE_TYPE, ResourceType.VPN_GATEWAY).put(FilterName.RESOURCE_TYPE, ResourceType.INTERNET_GATEWAY).build()); + request = binder.bindToRequest(request, ImmutableMap.>builder().put(FilterName.RESOURCE_TYPE, ImmutableSet.of(ResourceType.VPN_GATEWAY, ResourceType.INTERNET_GATEWAY)).build()); assertEquals(request.getPayload().getRawContent(), "Filter.1.Name=resource-type&Filter.1.Value.1=vpn-gateway&Filter.1.Value.2=internet-gateway"); } public void testMultipleKeys() { HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build(); - request = binder.bindToRequest(request, ImmutableSetMultimap.builder().put(FilterName.KEY, "one").put(FilterName.KEY, "two").build()); + request = binder.bindToRequest(request, ImmutableMap.>builder().put(FilterName.KEY, ImmutableSet.of("one", "two")).build()); assertEquals(request.getPayload().getRawContent(), "Filter.1.Name=key&Filter.1.Value.1=one&Filter.1.Value.2=two"); } public void testkeyWithValue() { HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build(); - request = binder.bindToRequest(request, ImmutableSetMultimap.builder().put(FilterName.KEY, "one").put(FilterName.VALUE, "alpha").build()); + request = binder.bindToRequest(request, ImmutableMap.>builder().put(FilterName.KEY, ImmutableSet.of("one")).put(FilterName.VALUE, ImmutableSet.of("alpha")).build()); assertEquals(request.getPayload().getRawContent(), "Filter.1.Name=key&Filter.1.Value.1=one&Filter.2.Name=value&Filter.2.Value.1=alpha"); } public void testAnyKey() { HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build(); - request = binder.bindToRequest(request, ImmutableSetMultimap.builder().put(FilterName.KEY, "*").build()); - assertEquals(request.getPayload().getRawContent(), "Filter.1.Name=key&Filter.1.Value.1=%2A"); + request = binder.bindToRequest(request, ImmutableMap.>builder().put(FilterName.KEY, ImmutableSet.of()).build()); + assertEquals(request.getPayload().getRawContent(), "Filter.1.Name=key"); } - public void testResourceTypeWithValuesBuilder() { + public void testMultipleResourceTypesBuilder() { HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build(); request = binder.bindToRequest(request, TagFilters.filters().vpnGateway().internetGateway().build()); assertEquals(request.getPayload().getRawContent(), "Filter.1.Name=resource-type&Filter.1.Value.1=vpn-gateway&Filter.1.Value.2=internet-gateway"); @@ -81,7 +82,7 @@ public class BindTagFiltersToIndexedFormParamsTest { assertEquals(request.getPayload().getRawContent(), "Filter.1.Name=key&Filter.1.Value.1=one&Filter.1.Value.2=two"); } - public void testkeyWithValueBuilder() { + public void testKeyWithValueBuilder() { HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build(); request = binder.bindToRequest(request, TagFilters.filters().keyValuePair("one", "alpha").build()); assertEquals(request.getPayload().getRawContent(), "Filter.1.Name=key&Filter.1.Value.1=one&Filter.2.Name=value&Filter.2.Value.1=alpha"); @@ -90,7 +91,7 @@ public class BindTagFiltersToIndexedFormParamsTest { public void testAnyKeyBuilder() { HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build(); request = binder.bindToRequest(request, TagFilters.filters().anyKey().build()); - assertEquals(request.getPayload().getRawContent(), "Filter.1.Name=key&Filter.1.Value.1=%2A"); + assertEquals(request.getPayload().getRawContent(), "Filter.1.Name=key"); } @Test(expectedExceptions = IllegalArgumentException.class) diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/TagAsyncClientTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/TagAsyncClientTest.java index ac088fc11c..4b0292f020 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/TagAsyncClientTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/TagAsyncClientTest.java @@ -22,7 +22,7 @@ import java.io.IOException; import java.lang.reflect.Method; import java.util.Map; -import org.jclouds.aws.ec2.util.TagFilters.FilterName; +import org.jclouds.aws.ec2.util.TagFilters; import org.jclouds.aws.ec2.xml.DescribeTagsResponseHandler; import org.jclouds.http.HttpRequest; import org.jclouds.http.functions.ParseSax; @@ -34,8 +34,6 @@ import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; import com.google.inject.TypeLiteral; /** @@ -79,8 +77,8 @@ public class TagAsyncClientTest extends BaseAWSEC2AsyncClientTestof()); + Method method = TagAsyncClient.class.getMethod("describeTagsInRegion", String.class, Map.class); + HttpRequest request = processor.createRequest(method, null, TagFilters.filters().build()); assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1"); assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n"); @@ -95,8 +93,8 @@ public class TagAsyncClientTest extends BaseAWSEC2AsyncClientTest results = client.describeTagsInRegion(null, ImmutableMultimap.builder() - .put(FilterName.RESOURCE_ID, resourceId) - .put(FilterName.RESOURCE_TYPE, resourceType) - .put(FilterName.KEY, key) - .put(FilterName.VALUE, value) - .build()); + Set results = client.describeTagsInRegion(null, TagFilters.filters().resourceId(resourceId).resourceType(resourceType).keyValuePair(key, value).build()); assertNotNull(results); assertEquals(results.size(), 1); Tag tag = Iterables.getOnlyElement(results);