You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ab...@apache.org on 2013/07/01 21:13:10 UTC

[05/20] JCLOUDS-150 - Removal of async from AWS - specifically EC2

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceAsyncClient.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceAsyncClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceAsyncClient.java
deleted file mode 100644
index bf773cd..0000000
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceAsyncClient.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF 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.ec2.services;
-
-import static org.jclouds.aws.reference.FormParameters.ACTION;
-
-import java.util.Set;
-
-import javax.inject.Named;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-
-import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
-import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
-import org.jclouds.aws.ec2.binders.BindLaunchSpecificationToFormParams;
-import org.jclouds.aws.ec2.binders.BindSpotInstanceRequestIdsToIndexedFormParams;
-import org.jclouds.aws.ec2.domain.LaunchSpecification;
-import org.jclouds.aws.ec2.domain.Spot;
-import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
-import org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions;
-import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions;
-import org.jclouds.aws.ec2.xml.DescribeSpotPriceHistoryResponseHandler;
-import org.jclouds.aws.ec2.xml.SpotInstanceHandler;
-import org.jclouds.aws.ec2.xml.SpotInstancesHandler;
-import org.jclouds.aws.filters.FormSigner;
-import org.jclouds.javax.annotation.Nullable;
-import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
-import org.jclouds.rest.annotations.BinderParam;
-import org.jclouds.rest.annotations.EndpointParam;
-import org.jclouds.rest.annotations.Fallback;
-import org.jclouds.rest.annotations.FormParams;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.VirtualHost;
-import org.jclouds.rest.annotations.XMLResponseParser;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides access to EC2 Spot Instances via their REST API.
- * <p/>
- * 
- * @author Adrian Cole
- */
-@RequestFilters(FormSigner.class)
-@VirtualHost
-public interface SpotInstanceAsyncClient {
-
-   /**
-    * @see SpotInstanceClient#describeSpotInstanceRequestsInRegion
-    */
-   @Named("DescribeSpotInstanceRequests")
-   @POST
-   @Path("/")
-   @FormParams(keys = ACTION, values = "DescribeSpotInstanceRequests")
-   @Fallback(EmptySetOnNotFoundOr404.class)
-   @XMLResponseParser(SpotInstancesHandler.class)
-   ListenableFuture<? extends Set<SpotInstanceRequest>> describeSpotInstanceRequestsInRegion(
-         @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
-         @BinderParam(BindSpotInstanceRequestIdsToIndexedFormParams.class) String... requestIds);
-
-   /**
-    * @see SpotInstanceClient#requestSpotInstanceInRegion
-    */
-   @Named("RequestSpotInstances")
-   @POST
-   @Path("/")
-   @FormParams(keys = ACTION, values = "RequestSpotInstances")
-   @XMLResponseParser(SpotInstanceHandler.class)
-   ListenableFuture<SpotInstanceRequest> requestSpotInstanceInRegion(
-         @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
-         @FormParam("SpotPrice") float spotPrice, @FormParam("LaunchSpecification.ImageId") String imageId,
-         @FormParam("LaunchSpecification.InstanceType") String instanceType);
-
-   /**
-    * @see SpotInstanceClient#requestSpotInstancesInRegion
-    */
-   @Named("RequestSpotInstances")
-   @POST
-   @Path("/")
-   @FormParams(keys = ACTION, values = "RequestSpotInstances")
-   @XMLResponseParser(SpotInstancesHandler.class)
-   ListenableFuture<? extends Set<SpotInstanceRequest>> requestSpotInstancesInRegion(
-         @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
-         @FormParam("SpotPrice") float spotPrice, @FormParam("InstanceCount") int instanceCount,
-         @BinderParam(BindLaunchSpecificationToFormParams.class) LaunchSpecification launchSpec,
-         RequestSpotInstancesOptions... options);
-
-   /**
-    * @see SpotInstanceClient#describeSpotPriceHistoryInRegion
-    */
-   @Named("DescribeSpotPriceHistory")
-   @POST
-   @Path("/")
-   @FormParams(keys = ACTION, values = "DescribeSpotPriceHistory")
-   @XMLResponseParser(DescribeSpotPriceHistoryResponseHandler.class)
-   @Fallback(EmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<Spot>> describeSpotPriceHistoryInRegion(
-         @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
-         DescribeSpotPriceHistoryOptions... options);
-
-   /**
-    * @see SpotInstanceClient#cancelSpotInstanceRequestsInRegion
-    */
-   @Named("CancelSpotInstanceRequests")
-   @POST
-   @Path("/")
-   @FormParams(keys = ACTION, values = "CancelSpotInstanceRequests")
-   @Fallback(VoidOnNotFoundOr404.class)
-   ListenableFuture<Void> cancelSpotInstanceRequestsInRegion(
-         @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
-         @BinderParam(BindSpotInstanceRequestIdsToIndexedFormParams.class) String... requestIds);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceClient.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceClient.java
deleted file mode 100644
index d7ee047..0000000
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/SpotInstanceClient.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF 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.ec2.services;
-
-import java.util.Set;
-import org.jclouds.aws.ec2.domain.LaunchSpecification;
-import org.jclouds.aws.ec2.domain.Spot;
-import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
-import org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions;
-import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions;
-import org.jclouds.javax.annotation.Nullable;
-
-/**
- * Provides Spot Instance services for EC2. For more information, refer to the Amazon EC2 Developer
- * Guide.
- * <p/>
- * 
- * @author Adrian Cole
- */
-public interface SpotInstanceClient {
-   /**
-    * Describes Spot Instance requests. Spot Instances are instances that Amazon EC2 starts on your
-    * behalf when the maximum price that you specify exceeds the current Spot Price. Amazon EC2
-    * periodically sets the Spot Price based on available Spot Instance capacity and current spot
-    * instance requests. For conceptual information about Spot Instances, refer to the Amazon
-    * Elastic Compute Cloud Developer Guide or Amazon Elastic Compute Cloud User Guide.
-    * 
-    * @param region
-    *           Region where the spot instance service is running
-    * @param requestIds
-    *           Specifies the ID of the Spot Instance request.
-    * 
-    * @see #requestSpotInstancesInRegion
-    * @see #cancelSpotInstanceRequestsInRegion
-    * @see #describeSpotPriceHistoryInRegion
-    * @see <a href=
-    *      "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSpotInstanceRequests.html"
-    *      />
-    * @return TODO
-    */
-   Set<SpotInstanceRequest> describeSpotInstanceRequestsInRegion(@Nullable String region, String... requestIds);
-
-   /**
-    * request a single spot instance
-    * 
-    * @param region
-    *           Region where the spot instance service is running
-    * @param spotPrice
-    *           Specifies the maximum hourly price for any Spot Instance launched to fulfill the
-    *           request.
-    * @param imageId
-    *           The AMI ID.
-    * @param instanceType
-    *           The instance type (ex. m1.small)
-    * @return spot instance request
-    * @see #requestSpotInstancesInRegion
-    */
-   SpotInstanceRequest requestSpotInstanceInRegion(@Nullable String region, float spotPrice, String imageId,
-         String instanceType);
-
-   /**
-    * Creates a Spot Instance request. Spot Instances are instances that Amazon EC2 starts on your
-    * behalf when the maximum price that you specify exceeds the current Spot Price. Amazon EC2
-    * periodically sets the Spot Price based on available Spot Instance capacity and current spot
-    * instance requests. For conceptual information about Spot Instances, refer to the Amazon
-    * Elastic Compute Cloud Developer Guide or Amazon Elastic Compute Cloud User Guide.
-    * 
-    * @param region
-    *           Region where the spot instance service is running
-    * @param spotPrice
-    *           Specifies the maximum hourly price for any Spot Instance launched to fulfill the
-    *           request.
-    * @param instanceCount
-    *           number of instances to request
-    * @param launchSpec
-    *           includes at least The AMI ID and instance type (ex. m1.small)
-    * @param options
-    *           options including expiration time or grouping
-    * 
-    * @see #describeSpotInstanceRequestsInRegion
-    * @see #cancelSpotInstanceRequestsInRegion
-    * @see #describeSpotPriceHistoryInRegion
-    * @see <a href=
-    *      "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-RequestSpotInstances.html"
-    *      />
-    * @return set of spot instance requests
-    */
-   Set<SpotInstanceRequest> requestSpotInstancesInRegion(@Nullable String region, float spotPrice, int instanceCount,
-         LaunchSpecification launchSpec, RequestSpotInstancesOptions... options);
-
-   /**
-    * 
-    * Describes Spot Price history. Spot Instances are instances that Amazon EC2 starts on your
-    * behalf when the maximum price that you specify exceeds the current Spot Price. Amazon EC2
-    * periodically sets the Spot Price based on available Spot Instance capacity and current spot
-    * instance requests. For conceptual information about Spot Instances, refer to the Amazon
-    * Elastic Compute Cloud Developer Guide or Amazon Elastic Compute Cloud User Guide.
-    * 
-    * @param region
-    *           Region where the spot instance service is running
-    * @param options
-    *           options to control the list
-    * 
-    * @see #describeSpotInstanceRequestsInRegion
-    * @see #requestSpotInstancesInRegion
-    * @see #cancelSpotInstanceRequestsInRegion
-    * @see <a href=
-    *      "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSpotInstanceRequests.html"
-    *      />
-    * @return TODO
-    */
-   Set<Spot> describeSpotPriceHistoryInRegion(@Nullable String region, DescribeSpotPriceHistoryOptions... options);
-
-   /**
-    * Cancels one or more Spot Instance requests. Spot Instances are instances that Amazon EC2
-    * starts on your behalf when the maximum price that you specify exceeds the current Spot Price.
-    * Amazon EC2 periodically sets the Spot Price based on available Spot Instance capacity and
-    * current spot instance requests. For conceptual information about Spot Instances, refer to the
-    * Amazon Elastic Compute Cloud Developer Guide or Amazon Elastic Compute Cloud User Guide.
-    * 
-    * @param region
-    *           Region where the spot instance service is running
-    * @param requestIds
-    *           Specifies the ID of the Spot Instance request.
-    * 
-    * @see #describeSpotInstanceRequestsInRegion
-    * @see #requestSpotInstancesInRegion
-    * @see #describeSpotPriceHistoryInRegion
-    * @see <a href=
-    *      "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CancelSpotInstanceRequests.html"
-    *      />
-    * @return TODO
-    */
-   String cancelSpotInstanceRequestsInRegion(@Nullable String region, String... requestIds);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/AWSEC2AsyncClientTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/AWSEC2AsyncClientTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/AWSEC2AsyncClientTest.java
deleted file mode 100644
index 838fa54..0000000
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/AWSEC2AsyncClientTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF 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.ec2;
-
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
-
-import org.jclouds.aws.ec2.services.BaseAWSEC2AsyncClientTest;
-import org.jclouds.http.HttpRequest;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-/**
- * Tests behavior of {@code AWSEC2AsyncClient}
- * 
- * @author Adrian Cole
- */
-// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
-@Test(groups = "unit", testName = "AWSEC2AsyncClientTest")
-public class AWSEC2AsyncClientTest extends BaseAWSEC2AsyncClientTest<AWSEC2AsyncClient> {
-
-   private AWSEC2AsyncClient asyncClient;
-   private AWSEC2Client syncClient;
-
-   public void testSync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException {
-      assert syncClient.getAMIServices() != null;
-      assert syncClient.getAvailabilityZoneAndRegionServices() != null;
-      assert syncClient.getElasticBlockStoreServices() != null;
-      assert syncClient.getElasticIPAddressServices() != null;
-      assert syncClient.getInstanceServices() != null;
-      assert syncClient.getKeyPairServices() != null;
-      assert syncClient.getMonitoringServices() != null;
-      assert syncClient.getSecurityGroupServices() != null;
-      assert syncClient.getPlacementGroupServices() != null;
-      assert syncClient.getWindowsServices() != null;
-
-   }
-
-   public void testAsync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException {
-      assert asyncClient.getAMIServices() != null;
-      assert asyncClient.getAvailabilityZoneAndRegionServices() != null;
-      assert asyncClient.getElasticBlockStoreServices() != null;
-      assert asyncClient.getElasticIPAddressServices() != null;
-      assert asyncClient.getInstanceServices() != null;
-      assert asyncClient.getKeyPairServices() != null;
-      assert asyncClient.getMonitoringServices() != null;
-      assert asyncClient.getSecurityGroupServices() != null;
-      assert asyncClient.getPlacementGroupServices() != null;
-      assert asyncClient.getWindowsServices() != null;
-   }
-
-   @BeforeClass
-   @Override
-   protected void setupFactory() throws IOException {
-      super.setupFactory();
-      asyncClient = injector.getInstance(AWSEC2AsyncClient.class);
-      syncClient = injector.getInstance(AWSEC2Client.class);
-   }
-
-   @Override
-   protected void checkFilters(HttpRequest request) {
-
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceLiveTest.java
index ae39523..235e596 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceLiveTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceLiveTest.java
@@ -30,10 +30,10 @@ import java.util.concurrent.TimeUnit;
 import org.jclouds.ContextBuilder;
 import org.jclouds.aws.cloudwatch.AWSCloudWatchProviderMetadata;
 import org.jclouds.aws.ec2.AWSEC2ApiMetadata;
-import org.jclouds.aws.ec2.AWSEC2Client;
+import org.jclouds.aws.ec2.AWSEC2Api;
 import org.jclouds.aws.ec2.domain.AWSRunningInstance;
 import org.jclouds.aws.ec2.domain.MonitoringState;
-import org.jclouds.aws.ec2.services.AWSSecurityGroupClient;
+import org.jclouds.aws.ec2.features.AWSSecurityGroupApi;
 import org.jclouds.cloudwatch.CloudWatchApi;
 import org.jclouds.cloudwatch.domain.Dimension;
 import org.jclouds.cloudwatch.domain.EC2Constants;
@@ -46,12 +46,12 @@ import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.predicates.NodePredicates;
 import org.jclouds.domain.LoginCredentials;
-import org.jclouds.ec2.EC2Client;
+import org.jclouds.ec2.EC2Api;
 import org.jclouds.ec2.compute.EC2ComputeServiceLiveTest;
 import org.jclouds.ec2.domain.KeyPair;
 import org.jclouds.ec2.domain.SecurityGroup;
-import org.jclouds.ec2.services.InstanceClient;
-import org.jclouds.ec2.services.KeyPairClient;
+import org.jclouds.ec2.features.InstanceApi;
+import org.jclouds.ec2.features.KeyPairApi;
 import org.jclouds.net.domain.IpProtocol;
 import org.jclouds.scriptbuilder.domain.Statements;
 import org.testng.annotations.Test;
@@ -78,14 +78,11 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
    public void testExtendedOptionsAndLogin() throws Exception {
       String region = "us-west-2";
 
-      AWSSecurityGroupClient securityGroupClient = AWSEC2Client.class.cast(
-               view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi()).getSecurityGroupServices();
+      AWSSecurityGroupApi securityGroupApi = view.unwrapApi(AWSEC2Api.class).getSecurityGroupApi().get();
 
-      KeyPairClient keyPairClient = EC2Client.class.cast(view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi())
-               .getKeyPairServices();
+      KeyPairApi keyPairApi = view.unwrapApi(AWSEC2Api.class).getKeyPairApi().get();
 
-      InstanceClient instanceClient = EC2Client.class.cast(view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi())
-               .getInstanceServices();
+      InstanceApi instanceApi = view.unwrapApi(AWSEC2Api.class).getInstanceApi().get();
 
       String group = this.group + "o";
 
@@ -105,20 +102,20 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
 
       String startedId = null;
       try {
-         cleanupExtendedStuffInRegion(region, securityGroupClient, keyPairClient, group);
+         cleanupExtendedStuffInRegion(region, securityGroupApi, keyPairApi, group);
 
          Thread.sleep(3000);// eventual consistency if deletes actually occurred.
 
          // create a security group that allows ssh in so that our scripts later
          // will work
-         String groupId = securityGroupClient.createSecurityGroupInRegionAndReturnId(region, group, group);
+         String groupId = securityGroupApi.createSecurityGroupInRegionAndReturnId(region, group, group);
 
-         securityGroupClient.authorizeSecurityGroupIngressInRegion(region, groupId, permit(IpProtocol.TCP).port(22));
+         securityGroupApi.authorizeSecurityGroupIngressInRegion(region, groupId, permit(IpProtocol.TCP).port(22));
 
          template.getOptions().as(AWSEC2TemplateOptions.class).securityGroupIds(groupId);
 
          // create a keypair to pass in as well
-         KeyPair result = keyPairClient.createKeyPairInRegion(region, group);
+         KeyPair result = keyPairApi.createKeyPairInRegion(region, group);
          template.getOptions().as(AWSEC2TemplateOptions.class).keyPair(result.getKeyName());
 
          // pass in the private key, so that we can run a script with it
@@ -136,7 +133,7 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
 
          startedId = first.getProviderId();
 
-         AWSRunningInstance instance = AWSRunningInstance.class.cast(getOnlyElement(getOnlyElement(instanceClient
+         AWSRunningInstance instance = AWSRunningInstance.class.cast(getOnlyElement(getOnlyElement(instanceApi
                   .describeInstancesInRegion(region, startedId))));
 
          assertEquals(instance.getKeyName(), group);
@@ -179,7 +176,7 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
          assertEquals(newTreeSet(instance.getGroupNames()), ImmutableSortedSet.<String> of("jclouds#" + group, group));
 
          // make sure our dummy group has no rules
-         SecurityGroup secgroup = getOnlyElement(securityGroupClient.describeSecurityGroupsInRegion(instance
+         SecurityGroup secgroup = getOnlyElement(securityGroupApi.describeSecurityGroupsInRegion(instance
                   .getRegion(), "jclouds#" + group));
 
          assert secgroup.size() == 0 : secgroup;
@@ -192,10 +189,10 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
          client.destroyNodesMatching(NodePredicates.inGroup(group));
          if (startedId != null) {
             // ensure we didn't delete these resources!
-            assertEquals(keyPairClient.describeKeyPairsInRegion(region, group).size(), 1);
-            assertEquals(securityGroupClient.describeSecurityGroupsInRegion(region, group).size(), 1);
+            assertEquals(keyPairApi.describeKeyPairsInRegion(region, group).size(), 1);
+            assertEquals(securityGroupApi.describeSecurityGroupsInRegion(region, group).size(), 1);
          }
-         cleanupExtendedStuffInRegion(region, securityGroupClient, keyPairClient, group);
+         cleanupExtendedStuffInRegion(region, securityGroupApi, keyPairApi, group);
       }
    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateBuilderLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateBuilderLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateBuilderLiveTest.java
index 240105f..ca94b70 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateBuilderLiveTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateBuilderLiveTest.java
@@ -26,12 +26,14 @@ import java.util.Properties;
 import java.util.Set;
 
 import org.jclouds.aws.domain.Region;
+import org.jclouds.aws.ec2.AWSEC2Api;
 import org.jclouds.aws.ec2.AWSEC2ApiMetadata;
 import org.jclouds.aws.ec2.reference.AWSEC2Constants;
 import org.jclouds.compute.ComputeServiceContext;
 import org.jclouds.compute.domain.OsFamily;
 import org.jclouds.compute.domain.OsFamilyVersion64Bit;
 import org.jclouds.compute.domain.Template;
+import org.jclouds.ec2.EC2Api;
 import org.jclouds.ec2.EC2ApiMetadata;
 import org.jclouds.ec2.compute.EC2TemplateBuilderLiveTest;
 import org.jclouds.ec2.compute.predicates.EC2ImagePredicates;
@@ -40,7 +42,7 @@ import org.jclouds.ec2.domain.RootDeviceType;
 import org.jclouds.ec2.options.DescribeAvailabilityZonesOptions;
 import org.jclouds.ec2.options.DescribeRegionsOptions;
 import org.jclouds.ec2.reference.EC2Constants;
-import org.jclouds.ec2.services.AvailabilityZoneAndRegionAsyncClient;
+import org.jclouds.ec2.features.AvailabilityZoneAndRegionApi;
 import org.jclouds.http.HttpCommand;
 import org.jclouds.http.internal.TrackingJavaUrlHttpCommandExecutorService;
 import org.jclouds.location.reference.LocationConstants;
@@ -336,9 +338,9 @@ public class AWSEC2TemplateBuilderLiveTest extends EC2TemplateBuilderLiveTest {
          throws NoSuchMethodException {
       assert commandsInvoked.size() == 2 : commandsInvoked;
       assertEquals(getInvokerOfRequestAtIndex(commandsInvoked, 0),
-            AvailabilityZoneAndRegionAsyncClient.class.getMethod("describeRegions", DescribeRegionsOptions[].class));
+            AvailabilityZoneAndRegionApi.class.getMethod("describeRegions", DescribeRegionsOptions[].class));
       assertEquals(getInvokerOfRequestAtIndex(commandsInvoked, 1),
-            AvailabilityZoneAndRegionAsyncClient.class.getMethod("describeAvailabilityZonesInRegion", String.class,
+            AvailabilityZoneAndRegionApi.class.getMethod("describeAvailabilityZonesInRegion", String.class,
                   DescribeAvailabilityZonesOptions[].class));
    }
 
@@ -355,8 +357,8 @@ public class AWSEC2TemplateBuilderLiveTest extends EC2TemplateBuilderLiveTest {
    
    @Test
    public void testAssignability() {
-      view.unwrap(EC2ApiMetadata.CONTEXT_TOKEN);
-      view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN);
+      view.unwrapApi(EC2Api.class);
+      view.unwrapApi(AWSEC2Api.class);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/extensions/AWSEC2ImageExtensionLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/extensions/AWSEC2ImageExtensionLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/extensions/AWSEC2ImageExtensionLiveTest.java
index ae303c6..6481efd 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/extensions/AWSEC2ImageExtensionLiveTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/extensions/AWSEC2ImageExtensionLiveTest.java
@@ -18,7 +18,7 @@ package org.jclouds.aws.ec2.compute.extensions;
 
 import static com.google.common.collect.Iterables.transform;
 
-import org.jclouds.aws.ec2.AWSEC2Client;
+import org.jclouds.aws.ec2.AWSEC2Api;
 import org.jclouds.aws.util.AWSUtils;
 import org.jclouds.compute.domain.Image;
 import org.jclouds.compute.extensions.ImageExtension;
@@ -45,13 +45,13 @@ public class AWSEC2ImageExtensionLiveTest extends BaseImageExtensionLiveTest {
 
    @Override
    protected Iterable<? extends Image> listImages() {
-      AWSEC2Client client = view.utils().injector().getInstance(AWSEC2Client.class);
+      AWSEC2Api client = view.unwrapApi(AWSEC2Api.class);
       String[] parts = AWSUtils.parseHandle(imageId);
       String region = parts[0];
       String imageId = parts[1];
       EC2ImageParser parser = view.utils().injector().getInstance(EC2ImageParser.class);
       return transform(
-            client.getAMIServices().describeImagesInRegion(region, new DescribeImagesOptions().imageIds(imageId)),
+                       client.getAMIApi().get().describeImagesInRegion(region, new DescribeImagesOptions().imageIds(imageId)),
             parser);
    }
 

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/functions/PresentSpotRequestsAndInstancesTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/functions/PresentSpotRequestsAndInstancesTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/functions/PresentSpotRequestsAndInstancesTest.java
index de7360d..babe978 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/functions/PresentSpotRequestsAndInstancesTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/functions/PresentSpotRequestsAndInstancesTest.java
@@ -24,17 +24,18 @@ import static org.testng.Assert.assertEquals;
 
 import java.util.Set;
 
-import org.jclouds.aws.ec2.AWSEC2Client;
+import org.jclouds.aws.ec2.AWSEC2Api;
 import org.jclouds.aws.ec2.domain.AWSRunningInstance;
 import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
-import org.jclouds.aws.ec2.services.AWSInstanceClient;
-import org.jclouds.aws.ec2.services.SpotInstanceClient;
+import org.jclouds.aws.ec2.features.AWSInstanceApi;
+import org.jclouds.aws.ec2.features.SpotInstanceApi;
 import org.jclouds.ec2.compute.domain.RegionAndName;
 import org.jclouds.ec2.domain.Reservation;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
+import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
@@ -50,25 +51,25 @@ public class PresentSpotRequestsAndInstancesTest {
    @Test
    public void testWhenInstancesPresentSingleCall() {
 
-      AWSEC2Client client = createMock(AWSEC2Client.class);
-      AWSInstanceClient instanceClient = createMock(AWSInstanceClient.class);
+      AWSEC2Api client = createMock(AWSEC2Api.class);
+      AWSInstanceApi instanceApi = createMock(AWSInstanceApi.class);
       Function<SpotInstanceRequest, AWSRunningInstance> converter = createMock(Function.class);
 
-      expect(client.getInstanceServices()).andReturn(instanceClient);
+      expect(client.getInstanceApi()).andReturn((Optional) Optional.of(instanceApi));
       
       // avoid imatcher fail.  if you change this, be sure to check multiple jres
-      expect(instanceClient.describeInstancesInRegion("us-east-1", "i-aaaa", "i-bbbb")).andReturn(
+      expect(instanceApi.describeInstancesInRegion("us-east-1", "i-aaaa", "i-bbbb")).andReturn(
             Set.class.cast(ImmutableSet.of(Reservation.<AWSRunningInstance> builder().region("us-east-1")
                   .instances(ImmutableSet.of(instance1, instance2)).build())));
 
-      replay(client, instanceClient, converter);
+      replay(client, instanceApi, converter);
 
       PresentSpotRequestsAndInstances fn = new PresentSpotRequestsAndInstances(client, converter);
 
       assertEquals(fn.apply(ImmutableSet.of(new RegionAndName("us-east-1", "i-aaaa"), new RegionAndName("us-east-1",
             "i-bbbb"))), ImmutableSet.of(instance1, instance2));
 
-      verify(client, instanceClient, converter);
+      verify(client, instanceApi, converter);
    }
 
    SpotInstanceRequest spot1 = createMock(SpotInstanceRequest.class);
@@ -80,20 +81,20 @@ public class PresentSpotRequestsAndInstancesTest {
       Function<SpotInstanceRequest, AWSRunningInstance> converter = Functions.forMap(ImmutableMap.of(spot1, instance1,
             spot2, instance2));
 
-      AWSEC2Client client = createMock(AWSEC2Client.class);
-      SpotInstanceClient spotClient = createMock(SpotInstanceClient.class);
+      AWSEC2Api client = createMock(AWSEC2Api.class);
+      SpotInstanceApi spotApi = createMock(SpotInstanceApi.class);
 
-      expect(client.getSpotInstanceServices()).andReturn(spotClient);
-      expect(spotClient.describeSpotInstanceRequestsInRegion("us-east-1", "sir-aaaa", "sir-bbbb")).andReturn(
+      expect(client.getSpotInstanceApi()).andReturn((Optional) Optional.of(spotApi));
+      expect(spotApi.describeSpotInstanceRequestsInRegion("us-east-1", "sir-aaaa", "sir-bbbb")).andReturn(
             ImmutableSet.of(spot1, spot2));
 
-      replay(client, spotClient);
+      replay(client, spotApi);
 
       PresentSpotRequestsAndInstances fn = new PresentSpotRequestsAndInstances(client, converter);
 
       assertEquals(fn.apply(ImmutableSet.of(new RegionAndName("us-east-1", "sir-aaaa"), new RegionAndName("us-east-1",
             "sir-bbbb"))), ImmutableSet.of(instance1, instance2));
 
-      verify(client, spotClient);
+      verify(client, spotApi);
    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/internal/BaseAWSEC2ComputeServiceExpectTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/internal/BaseAWSEC2ComputeServiceExpectTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/internal/BaseAWSEC2ComputeServiceExpectTest.java
index 193cd72..e643f9e 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/internal/BaseAWSEC2ComputeServiceExpectTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/internal/BaseAWSEC2ComputeServiceExpectTest.java
@@ -22,11 +22,11 @@ import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_GENERATE_INSTA
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.jclouds.aws.ec2.config.AWSEC2RestClientModule;
+import org.jclouds.aws.ec2.config.AWSEC2HttpApiModule;
 import org.jclouds.date.DateService;
 import org.jclouds.ec2.compute.internal.BaseEC2ComputeServiceExpectTest;
 import org.jclouds.http.HttpRequest;
-import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.ConfiguresHttpApi;
 import org.testng.annotations.BeforeClass;
 
 import com.google.common.base.Supplier;
@@ -100,8 +100,8 @@ public abstract class BaseAWSEC2ComputeServiceExpectTest extends BaseEC2ComputeS
                           .addFormParam("Filter.3.Value.1", "machine").build());
    }
 
-   @ConfiguresRestClient
-   protected static class TestAWSEC2RestClientModule extends AWSEC2RestClientModule {
+   @ConfiguresHttpApi
+   protected static class TestAWSEC2HttpApiModule extends AWSEC2HttpApiModule {
 
       @Override
       protected void configure() {
@@ -128,6 +128,6 @@ public abstract class BaseAWSEC2ComputeServiceExpectTest extends BaseEC2ComputeS
 
    @Override
    protected Module createModule() {
-      return new TestAWSEC2RestClientModule();
+      return new TestAWSEC2HttpApiModule();
    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeededTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeededTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeededTest.java
index 269a8f0..f61bf2e 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeededTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeededTest.java
@@ -27,7 +27,7 @@ import static org.testng.Assert.assertEquals;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
-import org.jclouds.aws.ec2.services.AWSSecurityGroupClient;
+import org.jclouds.aws.ec2.features.AWSSecurityGroupApi;
 import org.jclouds.ec2.compute.domain.RegionAndName;
 import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
 import org.jclouds.ec2.domain.SecurityGroup;
@@ -51,7 +51,7 @@ public class AWSEC2CreateSecurityGroupIfNeededTest {
    @Test
    public void testWhenPort22AndToItselfAuthorizesIngressOnce() throws ExecutionException {
 
-      AWSSecurityGroupClient client = createMock(AWSSecurityGroupClient.class);
+      AWSSecurityGroupApi client = createMock(AWSSecurityGroupApi.class);
       Predicate<RegionAndName> tester = Predicates.alwaysTrue();
 
       SecurityGroup group = createNiceMock(SecurityGroup.class);

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSAMIApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSAMIApiLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSAMIApiLiveTest.java
new file mode 100644
index 0000000..747e224
--- /dev/null
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSAMIApiLiveTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.ec2.features;
+
+import static org.jclouds.aws.ec2.options.AWSDescribeImagesOptions.Builder.filters;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.Set;
+
+import org.jclouds.aws.domain.Region;
+import org.jclouds.ec2.domain.Image;
+import org.jclouds.ec2.features.AMIApiLiveTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Tests behavior of {@code AMIApi}
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live", singleThreaded = true)
+public class AWSAMIApiLiveTest extends AMIApiLiveTest {
+
+   public AWSAMIApiLiveTest() {
+      provider = "aws-ec2";
+   }
+
+   public void testDescribeImagesCC() {
+      Set<? extends Image> ccResults = client.describeImagesInRegion(Region.US_EAST_1,
+            filters(ImmutableMultimap.<String, String> builder()//
+                  .put("virtualization-type", "hvm")//
+                  .put("architecture", "x86_64")//
+                  .putAll("owner-id", ImmutableSet.<String> of("137112412989", "099720109477"))//
+                  .put("hypervisor", "xen")//
+                  .put("state", "available")//
+                  .put("image-type", "machine")//
+                  .put("root-device-type", "ebs")//
+                  .build()).ownedBy("137112412989", "099720109477"));
+      assertNotNull(ccResults);
+      assert (ccResults.size() >= 34) : ccResults;
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSAMIApiTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSAMIApiTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSAMIApiTest.java
new file mode 100644
index 0000000..8f8a856
--- /dev/null
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSAMIApiTest.java
@@ -0,0 +1,497 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.ec2.features;
+
+import static org.jclouds.ec2.options.DescribeImagesOptions.Builder.executableBy;
+import static org.jclouds.reflect.Reflection2.method;
+
+import java.io.IOException;
+
+import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
+import org.jclouds.aws.ec2.xml.ProductCodesHandler;
+import org.jclouds.ec2.options.CreateImageOptions;
+import org.jclouds.ec2.options.DescribeImagesOptions;
+import org.jclouds.ec2.options.RegisterImageBackedByEbsOptions;
+import org.jclouds.ec2.options.RegisterImageOptions;
+import org.jclouds.ec2.xml.BlockDeviceMappingHandler;
+import org.jclouds.ec2.xml.DescribeImagesResponseHandler;
+import org.jclouds.ec2.xml.ImageIdHandler;
+import org.jclouds.ec2.xml.PermissionHandler;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.http.functions.ReleasePayloadAndReturn;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.reflect.Invokable;
+/**
+ * Tests behavior of {@code AWSAMIApi}
+ * 
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
+@Test(groups = "unit", testName = "AWSAMIApiTest")
+public class AWSAMIApiTest extends BaseAWSEC2ApiTest<AWSAMIApi> {
+   public AWSAMIApiTest() {
+      provider = "aws-ec2";
+   }
+
+   HttpRequest createImage = HttpRequest.builder().method("POST")
+                                        .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                        .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                        .addFormParam("Action", "CreateImage")
+                                        .addFormParam("InstanceId", "instanceId")
+                                        .addFormParam("Name", "name").build();
+
+   public void testCreateImage() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "createImageInRegion", String.class, String.class, String.class,
+               CreateImageOptions[].class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name", "instanceId"));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(createImage).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest createImageOptions = HttpRequest.builder().method("POST")
+                                               .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                               .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                               .addFormParam("Action", "CreateImage")
+                                               .addFormParam("Description", "description")
+                                               .addFormParam("InstanceId", "instanceId")
+                                               .addFormParam("Name", "name")
+                                               .addFormParam("NoReboot", "true").build();
+
+   public void testCreateImageOptions() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "createImageInRegion", String.class, String.class, String.class,
+               CreateImageOptions[].class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name", "instanceId", new CreateImageOptions()
+               .withDescription("description").noReboot()));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(createImageOptions).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest describeImages = HttpRequest.builder().method("POST")
+                                           .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                           .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                           .addFormParam("Action", "DescribeImages").build();
+
+   public void testDescribeImages() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "describeImagesInRegion", String.class,
+               DescribeImagesOptions[].class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList((String) null));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(describeImages).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, DescribeImagesResponseHandler.class);
+      assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
+
+      checkFilters(request);
+   }
+
+   HttpRequest describeImagesOptions = HttpRequest.builder().method("POST")
+                                                  .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                                  .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                                  .addFormParam("Action", "DescribeImages")
+                                                  .addFormParam("ExecutableBy", "me")
+                                                  .addFormParam("ImageId.1", "1")
+                                                  .addFormParam("ImageId.2", "2")
+                                                  .addFormParam("Owner.1", "fred")
+                                                  .addFormParam("Owner.2", "nancy").build();
+
+   public void testDescribeImagesOptions() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "describeImagesInRegion", String.class,
+               DescribeImagesOptions[].class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, executableBy("me").ownedBy("fred", "nancy").imageIds(
+               "1", "2")));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(describeImagesOptions).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, DescribeImagesResponseHandler.class);
+      assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
+
+      checkFilters(request);
+   }
+
+   HttpRequest deregisterImage = HttpRequest.builder().method("POST")
+                                            .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                            .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                            .addFormParam("Action", "DeregisterImage")
+                                            .addFormParam("ImageId", "imageId").build();
+
+   public void testDeregisterImage() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "deregisterImageInRegion", String.class, String.class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageId"));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(deregisterImage).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+      assertSaxResponseParserClassEquals(method, null);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest registerImageFromManifest = HttpRequest.builder().method("POST")
+                                                      .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                                      .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                                      .addFormParam("Action", "RegisterImage")
+                                                      .addFormParam("ImageLocation", "pathToManifest")
+                                                      .addFormParam("Name", "name").build();
+
+   public void testRegisterImageFromManifest() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "registerImageFromManifestInRegion", String.class, String.class,
+               String.class, RegisterImageOptions[].class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name", "pathToManifest"));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(registerImageFromManifest).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest registerImageFromManifestOptions = HttpRequest.builder().method("POST")
+                                                             .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                                             .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                                             .addFormParam("Action", "RegisterImage")
+                                                             .addFormParam("Description", "description")
+                                                             .addFormParam("ImageLocation", "pathToManifest")
+                                                             .addFormParam("Name", "name").build();
+
+   public void testRegisterImageFromManifestOptions() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "registerImageFromManifestInRegion", String.class, String.class,
+               String.class, RegisterImageOptions[].class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name", "pathToManifest", new RegisterImageOptions()
+               .withDescription("description")));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(registerImageFromManifestOptions).getPayload().getRawContent()
+            .toString(), "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest registerImageBackedByEBS = HttpRequest.builder().method("POST")
+                                                     .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                                     .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                                     .addFormParam("Action", "RegisterImage")
+                                                     .addFormParam("BlockDeviceMapping.0.DeviceName", "/dev/sda1")
+                                                     .addFormParam("BlockDeviceMapping.0.Ebs.SnapshotId", "snapshotId")
+                                                     .addFormParam("Name", "imageName")
+                                                     .addFormParam("RootDeviceName", "/dev/sda1").build();
+
+   public void testRegisterImageBackedByEBS() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "registerUnixImageBackedByEbsInRegion", String.class,
+               String.class, String.class, RegisterImageBackedByEbsOptions[].class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageName", "snapshotId"));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(registerImageBackedByEBS).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest registerImageBackedByEBSOptions = HttpRequest.builder().method("POST")
+                                                            .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                                            .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                                            .addFormParam("Action", "RegisterImage")
+                                                            .addFormParam("BlockDeviceMapping.0.DeviceName", "/dev/sda1")
+                                                            .addFormParam("BlockDeviceMapping.0.Ebs.SnapshotId", "snapshotId")
+                                                            .addFormParam("BlockDeviceMapping.1.DeviceName", "/dev/device")
+                                                            .addFormParam("BlockDeviceMapping.1.Ebs.DeleteOnTermination", "false")
+                                                            .addFormParam("BlockDeviceMapping.1.Ebs.SnapshotId", "snapshot")
+                                                            .addFormParam("BlockDeviceMapping.2.DeviceName", "/dev/newdevice")
+                                                            .addFormParam("BlockDeviceMapping.2.Ebs.DeleteOnTermination", "false")
+                                                            .addFormParam("BlockDeviceMapping.2.Ebs.VolumeSize", "100")
+                                                            .addFormParam("BlockDeviceMapping.2.VirtualName", "newblock")
+                                                            .addFormParam("Description", "description")
+                                                            .addFormParam("Name", "imageName")
+                                                            .addFormParam("RootDeviceName", "/dev/sda1").build();
+
+   public void testRegisterImageBackedByEBSOptions() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "registerUnixImageBackedByEbsInRegion", String.class,
+               String.class, String.class, RegisterImageBackedByEbsOptions[].class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageName", "snapshotId",
+               new RegisterImageBackedByEbsOptions().withDescription("description").addBlockDeviceFromSnapshot(
+                        "/dev/device", null, "snapshot").addNewBlockDevice("/dev/newdevice", "newblock", 100)));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(registerImageBackedByEBSOptions).getPayload().getRawContent()
+            .toString(), "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest getBlockDeviceMappingsForImage = HttpRequest.builder().method("POST")
+                                                           .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                                           .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                                           .addFormParam("Action", "DescribeImageAttribute")
+                                                           .addFormParam("Attribute", "blockDeviceMapping")
+                                                           .addFormParam("ImageId", "imageId").build();
+
+   public void testGetBlockDeviceMappingsForImage() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "getBlockDeviceMappingsForImageInRegion", String.class,
+               String.class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageId"));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(getBlockDeviceMappingsForImage).getPayload().getRawContent()
+            .toString(), "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, BlockDeviceMappingHandler.class);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest getLaunchPermissionForImage = HttpRequest.builder().method("POST")
+                                                        .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                                        .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                                        .addFormParam("Action", "DescribeImageAttribute")
+                                                        .addFormParam("Attribute", "launchPermission")
+                                                        .addFormParam("ImageId", "imageId").build();
+
+   public void testGetLaunchPermissionForImage() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "getLaunchPermissionForImageInRegion", String.class, String.class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageId"));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(getLaunchPermissionForImage).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, PermissionHandler.class);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest addLaunchPermission = HttpRequest.builder().method("POST")
+                                                          .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                                          .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                                          .addFormParam("Action", "ModifyImageAttribute")
+                                                          .addFormParam("Attribute", "launchPermission")
+                                                          .addFormParam("ImageId", "imageId")
+                                                          .addFormParam("OperationType", "add")
+                                                          .addFormParam("UserGroup.1", "all")
+                                                          .addFormParam("UserId.1", "bob")
+                                                          .addFormParam("UserId.2", "sue").build();
+
+   public void testAddLaunchPermissionsToImage() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "addLaunchPermissionsToImageInRegion", String.class,
+               Iterable.class, Iterable.class, String.class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, ImmutableList.of("bob", "sue"), ImmutableList
+               .of("all"), "imageId"));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(addLaunchPermission).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+      assertSaxResponseParserClassEquals(method, null);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest removeLaunchPermission = HttpRequest.builder().method("POST")
+                                                   .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                                   .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                                   .addFormParam("Action", "ModifyImageAttribute")
+                                                   .addFormParam("Attribute", "launchPermission")
+                                                   .addFormParam("ImageId", "imageId")
+                                                   .addFormParam("OperationType", "remove")
+                                                   .addFormParam("UserGroup.1", "all")
+                                                   .addFormParam("UserId.1", "bob")
+                                                   .addFormParam("UserId.2", "sue").build();
+
+   public void testRemoveLaunchPermissionsFromImage() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "removeLaunchPermissionsFromImageInRegion", String.class,
+               Iterable.class, Iterable.class, String.class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, ImmutableList.of("bob", "sue"), ImmutableList
+               .of("all"), "imageId"));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request, filter.filter(removeLaunchPermission).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+      assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+      assertSaxResponseParserClassEquals(method, null);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   HttpRequest resetLaunchPermissionsOnImage = HttpRequest.builder().method("POST")
+                                                          .endpoint("https://ec2.us-east-1.amazonaws.com/")
+                                                          .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+                                                          .addFormParam("Action", "ResetImageAttribute")
+                                                          .addFormParam("Attribute", "launchPermission")
+                                                          .addFormParam("ImageId", "imageId").build();
+
+   public void testResetLaunchPermissionsOnImage() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "resetLaunchPermissionsOnImageInRegion", String.class,
+               String.class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageId"));
+
+      request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
+      
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request,
+            filter.filter(resetLaunchPermissionsOnImage).getPayload().getRawContent().toString(),
+            "application/x-www-form-urlencoded", false);
+      assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+      assertSaxResponseParserClassEquals(method, null);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   public void testGetProductCodesForImage() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "getProductCodesForImageInRegion", String.class, String.class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageId"));
+
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(request,
+            "Action=DescribeImageAttribute&Attribute=productCodes&ImageId=imageId",
+            "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ParseSax.class);
+      assertSaxResponseParserClassEquals(method, ProductCodesHandler.class);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   public void testAddProductCodesToImage() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "addProductCodesToImageInRegion", String.class, Iterable.class,
+            String.class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, ImmutableList.of("code1", "code2"), "imageId"));
+
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(
+            request,
+            "Action=ModifyImageAttribute&OperationType=add&Attribute=productCodes&ImageId=imageId&ProductCode.1=code1&ProductCode.2=code2",
+            "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+      assertSaxResponseParserClassEquals(method, null);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+
+   public void testRemoveProductCodesFromImage() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(AWSAMIApi.class, "removeProductCodesFromImageInRegion", String.class,
+            Iterable.class, String.class);
+      GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, ImmutableList.of("code1", "code2"), "imageId"));
+
+      assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
+      assertPayloadEquals(
+            request,
+            "Action=ModifyImageAttribute&OperationType=remove&Attribute=productCodes&ImageId=imageId&ProductCode.1=code1&ProductCode.2=code2",
+            "application/x-www-form-urlencoded", false);
+
+      assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+      assertSaxResponseParserClassEquals(method, null);
+      assertFallbackClassEquals(method, null);
+
+      checkFilters(request);
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/5f3b8d3f/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSInstanceApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSInstanceApiLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSInstanceApiLiveTest.java
new file mode 100644
index 0000000..468de54
--- /dev/null
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSInstanceApiLiveTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.ec2.features;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.util.Set;
+
+import org.jclouds.aws.ec2.AWSEC2Api;
+import org.jclouds.aws.ec2.AWSEC2ApiMetadata;
+import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
+import org.jclouds.ec2.domain.Reservation;
+import org.jclouds.ec2.domain.RunningInstance;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Tests behavior of {@code AWSEC2Api}
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live", singleThreaded = true)
+public class AWSInstanceApiLiveTest extends BaseComputeServiceContextLiveTest {
+   public AWSInstanceApiLiveTest() {
+      provider = "aws-ec2";
+   }
+   
+   public static final String PREFIX = System.getProperty("user.name") + "-ec2";
+
+   private AWSInstanceApi client;
+   
+   @Override
+   @BeforeClass(groups = { "integration", "live" })
+   public void setupContext() {
+      super.setupContext();
+      client = view.unwrapApi(AWSEC2Api.class).getInstanceApi().get();
+   }
+
+   @Test
+   void testDescribeInstances() {
+      for (String region : view.unwrapApi(AWSEC2Api.class).getAvailabilityZoneAndRegionApi().get().describeRegions().keySet()) {
+         Set<? extends Reservation<? extends RunningInstance>> allResults = client.describeInstancesInRegion(region);
+         assertNotNull(allResults);
+         assert allResults.size() >= 0 : allResults.size();
+      }
+   }
+
+}